#39 Add krb5_pac_full_sign_compat() function [f37]
Closed 9 months ago by jrische. Opened 11 months ago by jrische.
rpms/ jrische/krb5 f37-rhbz2182135  into  f37

@@ -0,0 +1,673 @@ 

+ From 1007e9577794e24622c36243fdd18e07d0be88e6 Mon Sep 17 00:00:00 2001

+ From: Greg Hudson <ghudson@mit.edu>

+ Date: Thu, 22 Dec 2022 03:05:23 -0500

+ Subject: [PATCH] Add PAC full checksums

+ 

+ A paper by Tom Tervoort noted that computing the PAC privsvr checksum

+ over only the server checksum is vulnerable to collision attacks

+ (CVE-2022-37967).  In response, Microsoft has added a second KDC

+ checksum over the full contents of the PAC.  Generate and verify full

+ KDC checksums in PACs for service tickets.  Update the t_pac.c ticket

+ test case to use a ticket issued by a recent version of Active

+ Directory (provided by Stefan Metzmacher).

+ 

+ ticket: 9084 (new)

+ ---

+  doc/appdev/refs/macros/index.rst |   1 +

+  src/include/krb5/krb5.hin        |   1 +

+  src/lib/krb5/krb/pac.c           |  92 +++++++++--------

+  src/lib/krb5/krb/pac_sign.c      | 146 +++++++++++++++-----------

+  src/lib/krb5/krb/t_pac.c         | 171 ++++++++++++++++++-------------

+  src/tests/t_authdata.py          |   5 +-

+  6 files changed, 242 insertions(+), 174 deletions(-)

+ 

+ diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst

+ index a872b69bcf..ae0d3ff7bf 100644

+ --- a/doc/appdev/refs/macros/index.rst

+ +++ b/doc/appdev/refs/macros/index.rst

+ @@ -247,6 +247,7 @@ Public

+     KRB5_PAC_SERVER_CHECKSUM.rst

+     KRB5_PAC_TICKET_CHECKSUM.rst

+     KRB5_PAC_UPN_DNS_INFO.rst

+ +   KRB5_PAC_FULL_CHECKSUM.rst

+     KRB5_PADATA_AFS3_SALT.rst

+     KRB5_PADATA_AP_REQ.rst

+     KRB5_PADATA_AS_CHECKSUM.rst

+ diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin

+ index 5fe2a29f20..61c7ea985d 100644

+ --- a/src/include/krb5/krb5.hin

+ +++ b/src/include/krb5/krb5.hin

+ @@ -8192,6 +8192,7 @@ krb5_verify_authdata_kdc_issued(krb5_context context,

+  #define KRB5_PAC_TICKET_CHECKSUM   16 /**< Ticket checksum */

+  #define KRB5_PAC_ATTRIBUTES_INFO   17 /**< PAC attributes */

+  #define KRB5_PAC_REQUESTOR         18 /**< PAC requestor SID */

+ +#define KRB5_PAC_FULL_CHECKSUM     19 /**< KDC full checksum */

+  

+  struct krb5_pac_data;

+  /** PAC data structure to convey authorization information */

+ diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c

+ index 2f6ad4e1df..9c00178a28 100644

+ --- a/src/lib/krb5/krb/pac.c

+ +++ b/src/lib/krb5/krb/pac.c

+ @@ -500,7 +500,8 @@ zero_signature(krb5_context context, const krb5_pac pac, krb5_ui_4 type,

+      size_t i;

+  

+      assert(type == KRB5_PAC_SERVER_CHECKSUM ||

+ -           type == KRB5_PAC_PRIVSVR_CHECKSUM);

+ +           type == KRB5_PAC_PRIVSVR_CHECKSUM ||

+ +           type == KRB5_PAC_FULL_CHECKSUM);

+      assert(data->length >= pac->data.length);

+  

+      for (i = 0; i < pac->pac->cBuffers; i++) {

+ @@ -567,17 +568,17 @@ verify_checksum(krb5_context context, const krb5_pac pac, uint32_t buffer_type,

+  }

+  

+  static krb5_error_code

+ -verify_server_checksum(krb5_context context, const krb5_pac pac,

+ -                       const krb5_keyblock *server)

+ +verify_pac_checksums(krb5_context context, const krb5_pac pac,

+ +                     krb5_boolean expect_full_checksum,

+ +                     const krb5_keyblock *server, const krb5_keyblock *privsvr)

+  {

+      krb5_error_code ret;

+ -    krb5_data copy;             /* PAC with zeroed checksums */

+ +    krb5_data copy, server_checksum;

+  

+ +    /* Make a copy of the PAC with zeroed out server and privsvr checksums. */

+      ret = krb5int_copy_data_contents(context, &pac->data, &copy);

+      if (ret)

+          return ret;

+ -

+ -    /* Zero out both checksum buffers */

+      ret = zero_signature(context, pac, KRB5_PAC_SERVER_CHECKSUM, &copy);

+      if (ret)

+          goto cleanup;

+ @@ -585,32 +586,46 @@ verify_server_checksum(krb5_context context, const krb5_pac pac,

+      if (ret)

+          goto cleanup;

+  

+ -    ret = verify_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM, server,

+ -                          KRB5_KEYUSAGE_APP_DATA_CKSUM, &copy);

+ +    if (server != NULL) {

+ +        /* Verify the server checksum over the PAC copy. */

+ +        ret = verify_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM, server,

+ +                              KRB5_KEYUSAGE_APP_DATA_CKSUM, &copy);

+ +    }

+  

+ -cleanup:

+ -    free(copy.data);

+ -    return ret;

+ -}

+ +    if (privsvr != NULL && expect_full_checksum) {

+ +        /* Zero the full checksum buffer in the copy and verify the full

+ +         * checksum over the copy with all three checksums zeroed. */

+ +        ret = zero_signature(context, pac, KRB5_PAC_FULL_CHECKSUM, &copy);

+ +        if (ret)

+ +            goto cleanup;

+ +        ret = verify_checksum(context, pac, KRB5_PAC_FULL_CHECKSUM, privsvr,

+ +                              KRB5_KEYUSAGE_APP_DATA_CKSUM, &copy);

+ +        if (ret)

+ +            goto cleanup;

+ +    }

+  

+ -static krb5_error_code

+ -verify_kdc_checksum(krb5_context context, const krb5_pac pac,

+ -                    const krb5_keyblock *privsvr)

+ -{

+ -    krb5_error_code ret;

+ -    krb5_data server_checksum;

+ +    if (privsvr != NULL) {

+ +        /* Verify the privsvr checksum over the server checksum. */

+ +        ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,

+ +                                   &server_checksum);

+ +        if (ret)

+ +            return ret;

+ +        if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH)

+ +            return KRB5_BAD_MSIZE;

+ +        server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;

+ +        server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;

+  

+ -    ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,

+ -                               &server_checksum);

+ -    if (ret)

+ -        return ret;

+ -    if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH)

+ -        return KRB5_BAD_MSIZE;

+ -    server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;

+ -    server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;

+ +        ret = verify_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, privsvr,

+ +                              KRB5_KEYUSAGE_APP_DATA_CKSUM, &server_checksum);

+ +        if (ret)

+ +            goto cleanup;

+ +    }

+ +

+ +    pac->verified = TRUE;

+  

+ -    return verify_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, privsvr,

+ -                           KRB5_KEYUSAGE_APP_DATA_CKSUM, &server_checksum);

+ +cleanup:

+ +    free(copy.data);

+ +    return ret;

+  }

+  

+  /* Per MS-PAC 2.8.3, tickets encrypted to TGS and password change principals

+ @@ -638,6 +653,7 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,

+      krb5_authdata **authdata, *orig, **ifrel = NULL, **recoded_ifrel = NULL;

+      uint8_t z = 0;

+      krb5_authdata zpac = { KV5M_AUTHDATA, KRB5_AUTHDATA_WIN2K_PAC, 1, &z };

+ +    krb5_boolean is_service_tkt;

+      size_t i, j;

+  

+      *pac_out = NULL;

+ @@ -679,7 +695,8 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,

+      if (ret)

+          goto cleanup;

+  

+ -    if (privsvr != NULL && k5_pac_should_have_ticket_signature(server_princ)) {

+ +    is_service_tkt = k5_pac_should_have_ticket_signature(server_princ);

+ +    if (privsvr != NULL && is_service_tkt) {

+          /* To check the PAC ticket signatures, re-encode the ticket with the

+           * PAC contents replaced by a single zero. */

+          orig = ifrel[j];

+ @@ -703,8 +720,9 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,

+              goto cleanup;

+      }

+  

+ -    ret = krb5_pac_verify_ext(context, pac, enc_tkt->times.authtime, NULL,

+ -                              server, privsvr, FALSE);

+ +    ret = verify_pac_checksums(context, pac, is_service_tkt, server, privsvr);

+ +    if (ret)

+ +        goto cleanup;

+  

+      *pac_out = pac;

+      pac = NULL;

+ @@ -740,14 +758,8 @@ krb5_pac_verify_ext(krb5_context context,

+  {

+      krb5_error_code ret;

+  

+ -    if (server != NULL) {

+ -        ret = verify_server_checksum(context, pac, server);

+ -        if (ret != 0)

+ -            return ret;

+ -    }

+ -

+ -    if (privsvr != NULL) {

+ -        ret = verify_kdc_checksum(context, pac, privsvr);

+ +    if (server != NULL || privsvr != NULL) {

+ +        ret = verify_pac_checksums(context, pac, FALSE, server, privsvr);

+          if (ret != 0)

+              return ret;

+      }

+ @@ -759,8 +771,6 @@ krb5_pac_verify_ext(krb5_context context,

+              return ret;

+      }

+  

+ -    pac->verified = TRUE;

+ -

+      return 0;

+  }

+  

+ diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c

+ index 0f9581abbb..8ea61ac17b 100644

+ --- a/src/lib/krb5/krb/pac_sign.c

+ +++ b/src/lib/krb5/krb/pac_sign.c

+ @@ -187,26 +187,41 @@ k5_pac_encode_header(krb5_context context, krb5_pac pac)

+      return 0;

+  }

+  

+ -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)

+ +/* Find the buffer of type buftype in pac and write within it a checksum of

+ + * type cksumtype over data.  Set *cksum_out to the checksum. */

+ +static krb5_error_code

+ +compute_pac_checksum(krb5_context context, krb5_pac pac, uint32_t buftype,

+ +                     const krb5_keyblock *key, krb5_cksumtype cksumtype,

+ +                     const krb5_data *data, krb5_data *cksum_out)

+  {

+ -    return krb5_pac_sign_ext(context, pac, authtime, principal, server_key,

+ -                             privsvr_key, FALSE, data);

+ +    krb5_error_code ret;

+ +    krb5_data buf;

+ +    krb5_crypto_iov iov[2];

+ +

+ +    ret = k5_pac_locate_buffer(context, pac, buftype, &buf);

+ +    if (ret)

+ +        return ret;

+ +

+ +    assert(buf.length > PAC_SIGNATURE_DATA_LENGTH);

+ +    *cksum_out = make_data(buf.data + PAC_SIGNATURE_DATA_LENGTH,

+ +                           buf.length - PAC_SIGNATURE_DATA_LENGTH);

+ +    iov[0].flags = KRB5_CRYPTO_TYPE_DATA;

+ +    iov[0].data = *data;

+ +    iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;

+ +    iov[1].data = *cksum_out;

+ +    return krb5_c_make_checksum_iov(context, cksumtype, key,

+ +                                    KRB5_KEYUSAGE_APP_DATA_CKSUM, iov, 2);

+  }

+  

+ -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)

+ +static krb5_error_code

+ +sign_pac(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_boolean is_service_tkt, krb5_data *data)

+  {

+      krb5_error_code ret;

+ -    krb5_data server_cksum, privsvr_cksum;

+ +    krb5_data full_cksum, server_cksum, privsvr_cksum;

+      krb5_cksumtype server_cksumtype, privsvr_cksumtype;

+ -    krb5_crypto_iov iov[2];

+  

+      data->length = 0;

+      data->data = NULL;

+ @@ -214,67 +229,53 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,

+      if (principal != NULL) {

+          ret = k5_insert_client_info(context, pac, authtime, principal,

+                                      with_realm);

+ -        if (ret != 0)

+ +        if (ret)

+              return ret;

+      }

+  

+ -    /* Create zeroed buffers for both checksums */

+ +    /* Create zeroed buffers for all checksums. */

+      ret = k5_insert_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM,

+                               server_key, &server_cksumtype);

+ -    if (ret != 0)

+ +    if (ret)

+          return ret;

+ -

+      ret = k5_insert_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,

+                               privsvr_key, &privsvr_cksumtype);

+ -    if (ret != 0)

+ +    if (ret)

+          return ret;

+ +    if (is_service_tkt) {

+ +        ret = k5_insert_checksum(context, pac, KRB5_PAC_FULL_CHECKSUM,

+ +                                 privsvr_key, &privsvr_cksumtype);

+ +        if (ret)

+ +            return ret;

+ +    }

+  

+ -    /* Now, encode the PAC header so that the checksums will include it */

+ +    /* Encode the PAC header so that the checksums will include it. */

+      ret = k5_pac_encode_header(context, pac);

+ -    if (ret != 0)

+ -        return ret;

+ -

+ -    /* Generate the server checksum over the entire PAC */

+ -    ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,

+ -                               &server_cksum);

+ -    if (ret != 0)

+ +    if (ret)

+          return ret;

+  

+ -    assert(server_cksum.length > PAC_SIGNATURE_DATA_LENGTH);

+ -

+ -    iov[0].flags = KRB5_CRYPTO_TYPE_DATA;

+ -    iov[0].data = pac->data;

+ -

+ -    iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;

+ -    iov[1].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;

+ -    iov[1].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;

+ +    if (is_service_tkt) {

+ +        /* Generate a full KDC checksum over the whole PAC. */

+ +        ret = compute_pac_checksum(context, pac, KRB5_PAC_FULL_CHECKSUM,

+ +                                   privsvr_key, privsvr_cksumtype,

+ +                                   &pac->data, &full_cksum);

+ +        if (ret)

+ +            return ret;

+ +    }

+  

+ -    ret = krb5_c_make_checksum_iov(context, server_cksumtype,

+ -                                   server_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,

+ -                                   iov, sizeof(iov)/sizeof(iov[0]));

+ -    if (ret != 0)

+ +    /* Generate the server checksum over the whole PAC, including the full KDC

+ +     * checksum if we added one. */

+ +    ret = compute_pac_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM,

+ +                               server_key, server_cksumtype, &pac->data,

+ +                               &server_cksum);

+ +    if (ret)

+          return ret;

+  

+ -    /* Generate the privsvr checksum over the server checksum buffer */

+ -    ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,

+ +    /* Generate the privsvr checksum over the server checksum buffer. */

+ +    ret = compute_pac_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,

+ +                               privsvr_key, privsvr_cksumtype, &server_cksum,

+                                 &privsvr_cksum);

+ -    if (ret != 0)

+ -        return ret;

+ -

+ -    assert(privsvr_cksum.length > PAC_SIGNATURE_DATA_LENGTH);

+ -

+ -    iov[0].flags = KRB5_CRYPTO_TYPE_DATA;

+ -    iov[0].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;

+ -    iov[0].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;

+ -

+ -    iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;

+ -    iov[1].data.data = privsvr_cksum.data + PAC_SIGNATURE_DATA_LENGTH;

+ -    iov[1].data.length = privsvr_cksum.length - PAC_SIGNATURE_DATA_LENGTH;

+ -

+ -    ret = krb5_c_make_checksum_iov(context, privsvr_cksumtype,

+ -                                   privsvr_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,

+ -                                   iov, sizeof(iov)/sizeof(iov[0]));

+ -    if (ret != 0)

+ +    if (ret)

+          return ret;

+  

+      data->data = k5memdup(pac->data.data, pac->data.length, &ret);

+ @@ -288,6 +289,26 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,

+      return 0;

+  }

+  

+ +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)

+ +{

+ +    return sign_pac(context, pac, authtime, principal, server_key,

+ +                    privsvr_key, FALSE, 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)

+ +{

+ +    return sign_pac(context, pac, authtime, principal, server_key, privsvr_key,

+ +                    with_realm, FALSE, data);

+ +}

+ +

+  /* 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

+ @@ -359,6 +380,7 @@ krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,

+      krb5_error_code ret;

+      krb5_data *der_enc_tkt = NULL, pac_data = empty_data();

+      krb5_authdata **list, *pac_ad;

+ +    krb5_boolean is_service_tkt;

+      size_t count;

+  

+      /* Reallocate space for another authdata element in enc_tkt. */

+ @@ -377,7 +399,8 @@ krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,

+      memmove(list + 1, list, (count + 1) * sizeof(*list));

+      list[0] = pac_ad;

+  

+ -    if (k5_pac_should_have_ticket_signature(server_princ)) {

+ +    is_service_tkt = k5_pac_should_have_ticket_signature(server_princ);

+ +    if (is_service_tkt) {

+          ret = encode_krb5_enc_tkt_part(enc_tkt, &der_enc_tkt);

+          if (ret)

+              goto cleanup;

+ @@ -388,9 +411,8 @@ krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,

+              goto cleanup;

+      }

+  

+ -    ret = krb5_pac_sign_ext(context, pac, enc_tkt->times.authtime,

+ -                            client_princ, server, privsvr, with_realm,

+ -                            &pac_data);

+ +    ret = sign_pac(context, pac, enc_tkt->times.authtime, client_princ, server,

+ +                   privsvr, with_realm, is_service_tkt, &pac_data);

+      if (ret)

+          goto cleanup;

+  

+ diff --git a/src/lib/krb5/krb/t_pac.c b/src/lib/krb5/krb/t_pac.c

+ index 173bde7bab..81f1642ab0 100644

+ --- a/src/lib/krb5/krb/t_pac.c

+ +++ b/src/lib/krb5/krb/t_pac.c

+ @@ -607,78 +607,102 @@ check_pac(krb5_context context, int index, const unsigned char *pdata,

+  

+  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")

+ +    32, U("\x03\x73\x81\xEC\x43\x96\x7B\xC2\xAC\x3D\xF5\x2A\xAE\x95\xA6\x8E"

+ +          "\xBE\x24\x58\xDB\xCE\x52\x28\x20\xAF\x5E\xB7\x04\xA2\x22\x71\x4F")

+  };

+  

+  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")

+ +    0, ENCTYPE_AES256_CTS_HMAC_SHA1_96,

+ +    32, U("\x11\x4A\x84\xE3\x14\x8F\xAA\xB1\xFA\x7B\x53\x51\xB2\x8A\xC2\xF1"

+ +          "\xFD\x19\x6D\x61\xE0\xF3\xF2\x3E\x1F\xDB\xD3\xC1\x79\x7D\xC1\xEE")

+  };

+  

+ +/* A ticket issued by an Active Directory KDC (Windows Server 2022), containing

+ + * a PAC with a full checksum. */

+  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"

+ +    .length = 1307, .data =

+ +    "\x61\x82\x05\x17\x30\x82\x05\x13\xA0\x03\x02\x01\x05\xA1\x0F\x1B"

+ +    "\x0D\x57\x32\x30\x32\x32\x2D\x4C\x37\x2E\x42\x41\x53\x45\xA2\x2A"

+ +    "\x30\x28\xA0\x03\x02\x01\x01\xA1\x21\x30\x1F\x1B\x04\x63\x69\x66"

+ +    "\x73\x1B\x17\x77\x32\x30\x32\x32\x2D\x31\x31\x38\x2E\x77\x32\x30"

+ +    "\x32\x32\x2D\x6C\x37\x2E\x62\x61\x73\x65\xA3\x82\x04\xCD\x30\x82"

+ +    "\x04\xC9\xA0\x03\x02\x01\x12\xA1\x03\x02\x01\x05\xA2\x82\x04\xBB"

+ +    "\x04\x82\x04\xB7\x44\x5C\x7B\x5A\x3F\x2E\xA3\x50\x34\xDE\xB0\x69"

+ +    "\x23\x2D\x47\x89\x2C\xC0\xA3\xF9\xDD\x70\xAA\xA5\x1E\xFE\x74\xE5"

+ +    "\x19\xA2\x4F\x65\x6C\x9E\x00\xB4\x60\x00\x7C\x0C\x29\x43\x31\x99"

+ +    "\x77\x02\x73\xED\xB9\x40\xF5\xD2\xD1\xC9\x20\x0F\xE3\x38\xF9\xCC"

+ +    "\x5E\x2A\xBD\x1F\x91\x66\x1A\xD8\x2A\x80\x3C\x2C\x00\x3C\x1E\xC9"

+ +    "\x2A\x29\x19\x19\x96\x18\x54\x03\x97\x8F\x1D\x5F\xDB\xE9\x66\x68"

+ +    "\xCD\xB1\xD5\x00\x35\x69\x49\x45\xF1\x6A\x78\x7B\x37\x71\x87\x14"

+ +    "\x1C\x98\x4D\x69\xCB\x1B\xD8\xF5\xA3\xD8\x53\x4A\x75\x76\x62\xBA"

+ +    "\x6C\x3F\xEA\x8B\x97\x21\xCA\x8A\x46\x4B\x38\xDA\x09\x9F\x5A\xC8"

+ +    "\x38\xFF\x34\x97\x5B\xA2\xE5\xBA\xC9\x87\x17\xD8\x08\x05\x7A\x83"

+ +    "\x04\xD6\x02\x8E\x9B\x18\xB6\x40\x1A\xF7\x47\x25\x24\x3E\x37\x1E"

+ +    "\xF6\xC1\x3A\x1F\xCA\xB3\x43\x5A\xAE\x94\x83\x31\xAF\xFB\xEE\xED"

+ +    "\x46\x71\xEF\xE2\x37\x37\x15\xFE\x1B\x0B\x9E\xF8\x3E\x0C\x43\x96"

+ +    "\xB6\x0A\x04\x78\xF8\x5E\xAA\x33\x1F\xE2\x07\x5A\x8D\xC4\x4E\x32"

+ +    "\x6D\xD6\xA0\xC5\xEA\x3D\x12\x59\xD4\x41\x40\x4E\xA1\xD8\xBE\xED"

+ +    "\x17\xCB\x68\xCC\x59\xCB\x53\xB2\x0E\x58\x8A\xA9\x33\x7F\x6F\x2B"

+ +    "\x37\x89\x08\x44\xBA\xC7\x67\x17\xBB\x91\xF7\xC3\x0F\x00\xF8\xAA"

+ +    "\xA1\x33\xA6\x08\x47\xCA\xFA\xE8\x49\x27\x45\x46\xF1\xC1\xC3\x5F"

+ +    "\xE2\x45\x0A\x7D\x64\x52\x8C\x2E\xE1\xDE\xFF\xB2\x64\xEC\x69\x98"

+ +    "\x15\xDF\x9E\xB1\xEB\xD6\x9D\x08\x06\x4E\x73\xC1\x0B\x71\x21\x05"

+ +    "\x9E\xBC\xA2\x17\xCF\xB3\x70\xF4\xEF\xB8\x69\xA9\x94\x27\xFD\x5E"

+ +    "\x72\xB1\x2D\xD2\x20\x1B\x57\x80\xAB\x38\x97\xCF\x22\x68\x4F\xB8"

+ +    "\xB7\x17\x53\x25\x67\x0B\xED\xD1\x58\x20\x0D\x45\xF9\x09\xFA\xE7"

+ +    "\x61\x3E\xDB\xC2\x59\x7B\x3A\x3B\x59\x81\x51\xAA\xA4\x81\xF4\x96"

+ +    "\x3B\xE1\x6F\x6F\xF4\x8E\x68\x9E\xBA\x1E\x0F\xF2\x44\x68\x11\xFC"

+ +    "\x2B\x5F\xBE\xF2\xEA\x07\x80\xB9\xCA\x9E\x41\xBD\x2F\x81\xF5\x11"

+ +    "\x2A\x12\xF3\x4F\xD6\x12\x16\x0F\x21\x90\xF1\xD3\x1E\xF1\xA4\x94"

+ +    "\x46\xEA\x30\xF3\x84\x06\xC1\xA4\x51\xFC\x43\x35\xBD\xEF\x4D\x89"

+ +    "\x1D\xA5\x44\xB2\x69\xC4\x0F\xBF\x86\x01\x08\x44\x77\xD5\xB4\xB7"

+ +    "\x5C\x3F\xA7\xD4\x2F\x39\x73\x85\x88\xEE\xB1\x64\x1D\x80\x6C\xEE"

+ +    "\x6E\x31\x90\x92\x0D\xA1\xB7\xC4\x5C\xCC\xEE\x91\xC8\xCB\x11\x2D"

+ +    "\x4A\x1A\x7D\x43\x8F\xEB\x60\x09\xED\x1B\x07\x58\xBE\xBC\xBD\x29"

+ +    "\xF3\xB3\xA3\x4F\xC5\x8A\x30\x33\xB9\xA9\x9F\x43\x08\x27\x15\xC4"

+ +    "\x9C\x5D\x8E\xBD\x5C\x05\xC6\x05\x9C\x87\x60\x08\x1E\xE2\x52\xB8"

+ +    "\x45\x8D\x28\xB6\x2C\x15\x46\x74\x9F\x0E\xAA\x6B\x70\x3A\x2A\x55"

+ +    "\x45\x26\xB2\x58\x4D\x35\xA6\xF1\x96\xBE\x60\xB2\x71\x7B\xF8\x54"

+ +    "\xB9\x90\x21\x8E\xB9\x0F\x35\x98\x5E\x88\xEB\x1A\x53\xB4\x59\x7F"

+ +    "\xAF\x69\x1C\x61\x67\xF4\xF6\xBD\xAC\x24\xCD\xB7\xA9\x67\xE8\xA1"

+ +    "\x83\x85\x5F\x11\x74\x1F\xF7\x4C\x78\x36\xEF\x50\x74\x88\x58\x4B"

+ +    "\x1A\x9F\x84\x9A\x9A\x05\x92\xEC\x1D\xD5\xF3\xC4\x95\x51\x28\xE2"

+ +    "\x3F\x32\x87\xB2\xFD\x21\x27\x66\xE4\x6B\x85\x2F\xDC\x7B\xC0\x22"

+ +    "\xEB\x7A\x94\x20\x5A\x7B\xD3\x7A\xB9\x5B\xF8\x1A\x5A\x84\x4E\xA1"

+ +    "\x73\x41\x53\xD2\x60\xF7\x7C\xEE\x68\x59\x85\x80\xFC\x3D\x70\x4B"

+ +    "\x04\x32\xE7\xF2\xFD\xBD\xB3\xD9\x21\xE2\x37\x56\xA2\x16\xCC\xDE"

+ +    "\x8A\xD3\xBC\x71\xEF\x58\x19\x0E\x45\x8A\x5B\x53\xD6\x77\x30\x6A"

+ +    "\xA7\xF8\x68\x06\x4E\x07\xCA\xCE\x30\xD7\x35\xAB\x1A\xC7\x18\xD4"

+ +    "\xC6\x2F\x1A\xFF\xE9\x7A\x94\x0B\x76\x5E\x7E\x29\x0C\xE6\xD3\x3B"

+ +    "\x5B\x44\x96\xA8\xF1\x29\x23\x95\xD9\x79\xB3\x39\xFC\x76\xED\xE1"

+ +    "\x1E\x67\x4E\xF7\xE8\x7B\x7A\x12\x9E\xD8\x4B\x35\x09\x0A\xF2\xC1"

+ +    "\x63\x5B\xEE\xFD\x2A\xC2\xA6\x66\x30\x3C\x1F\x95\xAF\x65\x22\x95"

+ +    "\x14\x1D\xF5\xD5\xDC\x38\x79\x35\x1C\xCD\x24\x47\xE0\xFD\x08\xC8"

+ +    "\xF4\x15\x55\x9F\xD9\xC7\xAC\x3F\x67\xB3\x4F\xEB\x26\x7C\x8E\xD6"

+ +    "\x74\xB3\x0A\xCD\xE7\xFA\xBE\x7E\xA3\x3E\xEC\x61\x50\x77\x52\x56"

+ +    "\xCF\x90\x5D\x48\xFB\xD4\x2C\x6C\x61\x8B\xDD\x2B\xF5\x92\x1F\x30"

+ +    "\xBF\x3F\x80\x0D\x31\xDB\xB2\x0B\x7D\x84\xE3\xA6\x42\x7F\x00\x38"

+ +    "\x44\x02\xC5\xB8\xD9\x58\x29\x9D\x68\x5C\x32\x8B\x76\xAE\xED\x15"

+ +    "\xF9\x7C\xAE\x7B\xB6\x8E\xD6\x54\x24\xFF\xFA\x87\x05\xEF\x15\x08"

+ +    "\x5E\x4B\x21\xA2\x2F\x49\xE7\x0F\xC3\xD0\xB9\x49\x22\xEF\xD5\xCA"

+ +    "\xB2\x11\xF2\x17\xB6\x77\x24\x68\x76\xB2\x07\xF8\x0A\x73\xDD\x65"

+ +    "\x9C\x75\x64\xF7\xA1\xC6\x23\x08\x84\x72\x3E\x54\x2E\xEB\x9B\x40"

+ +    "\xA6\x83\x87\xEB\xB5\x00\x40\x4F\xE1\x72\x2A\x59\x3A\x06\x60\x29"

+ +    "\x7E\x25\x2F\xD8\x80\x40\x8C\x59\xCA\xCF\x8E\x44\xE4\x2D\x84\x7E"

+ +    "\xCB\xFD\x1E\x3B\xD5\xFF\x9A\xB9\x66\x93\x6D\x5E\xC8\xB7\x13\x26"

+ +    "\xD6\x38\x1B\x2B\xE1\x87\x96\x05\xD5\xF3\xAB\x68\xF7\x12\x62\x2C"

+ +    "\x58\xC1\xC9\x85\x3C\x72\xF1\x26\xEE\xC0\x09\x5F\x1D\x4B\xAC\x01"

+ +    "\x41\xC8\x12\xF8\xF3\x93\x43\x41\xFF\xEC\x0B\x80\xE2\xEE\x20\x85"

+ +    "\x25\xCD\x6C\x30\x8C\x0D\x24\x2E\xBA\x19\xEA\x28\x7F\xCF\xD5\x10"

+ +    "\x5C\xE9\xB2\x9D\x5F\x16\xE4\xC0\xF3\xCC\xD9\x68\x4A\x05\x08\x70"

+ +    "\x17\x26\xC8\x5C\x4A\xBF\x94\x6A\x0E\xD5\xDA\x67\x47\x4B\xAF\x44"

+ +    "\xE3\x94\xAA\x05\xDB\xA2\x49\x74\xFA\x5C\x69\xAB\x44\xB7\xF7\xBA"

+ +    "\xAE\x7A\x23\x87\xEB\x54\x7E\x80\xF1\x5B\x60\xA5\x93\xE5\xD4\x24"

+ +    "\x84\xF7\x0A\x16\x10\xBE\xE9\x4D\xD8\x6B\x15\x40\x5D\x74\xDA\x1B"

+ +    "\xFF\x2E\x4D\x17\x9D\x35\xF7\x0D\xCF\x66\x38\x0D\x8A\xE4\xDD\x6B"

+ +    "\xE1\x0F\x1F\xBD\xFD\x4F\x30\x37\x3F\x96\xB4\x92\x54\xD3\x9A\x7A"

+ +    "\xD1\x5B\x5B\xA9\x54\x16\xE6\x24\xAB\xD4\x23\x39\x7D\xD2\xC7\x09"

+ +    "\xFA\xD4\x86\x55\x4D\x60\xC2\x87\x67\x6B\xE6"

+  };

+  

+  static void

+ @@ -686,7 +710,7 @@ test_pac_ticket_signature(krb5_context context)

+  {

+      krb5_error_code ret;

+      krb5_ticket *ticket;

+ -    krb5_principal sprinc;

+ +    krb5_principal cprinc, sprinc;

+      krb5_authdata **authdata1, **authdata2;

+      krb5_pac pac, pac2, pac3;

+      uint32_t *list;

+ @@ -701,7 +725,13 @@ test_pac_ticket_signature(krb5_context context)

+      if (ret)

+          err(context, ret, "while decrypting ticket");

+  

+ -    ret = krb5_parse_name(context, "s1@CDOM.COM", &sprinc);

+ +    ret = krb5_parse_name(context, "administrator@W2022-L7.BASE", &cprinc);

+ +    if (ret)

+ +        err(context, ret, "krb5_parse_name");

+ +

+ +    ret = krb5_parse_name(context,

+ +                          "cifs/w2022-118.w2022-l7.base@W2022-L7.BASE",

+ +                          &sprinc);

+      if (ret)

+          err(context, ret, "krb5_parse_name");

+  

+ @@ -713,7 +743,7 @@ test_pac_ticket_signature(krb5_context context)

+  

+      /* In this test, the server is also the client. */

+      ret = krb5_pac_verify(context, pac, ticket->enc_part2->times.authtime,

+ -                          ticket->server, NULL, NULL);

+ +                          cprinc, NULL, NULL);

+      if (ret)

+          err(context, ret, "while verifying PAC client info");

+  

+ @@ -722,7 +752,7 @@ test_pac_ticket_signature(krb5_context context)

+      ticket->enc_part2->authorization_data = NULL;

+  

+      ret = krb5_kdc_sign_ticket(context, ticket->enc_part2, pac, sprinc,

+ -                               sprinc, &ticket_sig_server_key,

+ +                               cprinc, &ticket_sig_server_key,

+                                 &ticket_sig_krbtgt_key, FALSE);

+      if (ret)

+          err(context, ret, "while signing ticket");

+ @@ -781,6 +811,7 @@ test_pac_ticket_signature(krb5_context context)

+      krb5_pac_free(context, pac);

+      krb5_pac_free(context, pac2);

+      krb5_pac_free(context, pac3);

+ +    krb5_free_principal(context, cprinc);

+      krb5_free_principal(context, sprinc);

+      krb5_free_ticket(context, ticket);

+  }

+ diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py

+ index 2e01f46bcb..be3eaf7668 100644

+ --- a/src/tests/t_authdata.py

+ +++ b/src/tests/t_authdata.py

+ @@ -11,7 +11,7 @@ realm = K5Realm(krb5_conf=conf)

+  # container.

+  mark('baseline authdata')

+  out = realm.run(['./adata', realm.host_princ])

+ -if '?512: ' not in out or '^-42: Hello' not in out:

+ +if '?128: [6, 7, 10, 16, 19]' not in out or '^-42: Hello' not in out:

+      fail('expected authdata not seen for basic request')

+  

+  # Requested authdata is copied into the ticket, with KDC-only types

+ @@ -239,6 +239,9 @@ realm.run(['./s4u2proxy', usercache, 'service/2'])

+  out = realm.run(['./adata', '-p', realm.user_princ, 'service/2'])

+  if '+97: [indcl]' not in out or '[inds1]' in out:

+      fail('correct auth-indicator not seen for S4U2Proxy req')

+ +# Make sure a PAC with an S4U_DELEGATION_INFO(11) buffer is included.

+ +if '?128: [1, 6, 7, 10, 11, 16, 19]' not in out:

+ +    fail('PAC with delegation info not seen for S4U2Proxy req')

+  

+  # Get another S4U2Proxy ticket including request-authdata.

+  realm.run(['./s4u2proxy', usercache, 'service/2', '-2', 'proxy_ad'])

+ -- 

+ 2.39.2

+ 

@@ -0,0 +1,834 @@ 

+ From 7c9fc678b08a9fb53155a1acc3e2a817c5b13da4 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     |   7 ++

+  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              |   2 +

+  src/plugins/kdb/test/kdb_test.c  |   6 +-

+  11 files changed, 538 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 4bf64e7dfa..a872b69bcf 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 f8778075fc..5fe2a29f20 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

+ @@ -8186,6 +8186,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 */

+ @@ -8343,56 +8349,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 ab3cc3e5a4..485cf30dab 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 2fde08d1ae..b62f9049f0 100644

+ --- a/src/lib/krb5/krb/int-proto.h

+ +++ b/src/lib/krb5/krb/int-proto.h

+ @@ -391,4 +391,11 @@ k5_get_proxy_cred_from_kdc(krb5_context context, krb5_flags options,

+  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 df6e2ffbe6..0ff4f191d6 100644

+ --- a/src/lib/krb5/libkrb5.exports

+ +++ b/src/lib/krb5/libkrb5.exports

+ @@ -464,6 +464,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 cf690dbe42..b1610974b1 100644

+ --- a/src/lib/krb5_32.def

+ +++ b/src/lib/krb5_32.def

+ @@ -508,3 +508,5 @@ EXPORTS

+  	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 2e02e2141f..495bec42ad 100644

+ --- a/src/plugins/kdb/test/kdb_test.c

+ +++ b/src/plugins/kdb/test/kdb_test.c

+ @@ -700,7 +700,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;

+ @@ -709,7 +709,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;

+ @@ -722,7 +722,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

+ 

@@ -0,0 +1,258 @@ 

+ From 54b9a07f4167c1391b80fb177dd85c82f4d3f6b3 Mon Sep 17 00:00:00 2001

+ From: Greg Hudson <ghudson@mit.edu>

+ Date: Fri, 14 Jan 2022 02:05:58 -0500

+ Subject: [PATCH 3/5] Factor out PAC checksum verification

+ 

+ Reduce code repetition in PAC checksum handling by adding a helper

+ function.  Remove the unnecessary prefix on several function names.

+ ---

+  src/lib/krb5/krb/pac.c | 173 +++++++++++++----------------------------

+  1 file changed, 55 insertions(+), 118 deletions(-)

+ 

+ diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c

+ index 6eb23d8090..2f6ad4e1df 100644

+ --- a/src/lib/krb5/krb/pac.c

+ +++ b/src/lib/krb5/krb/pac.c

+ @@ -493,10 +493,8 @@ k5_pac_validate_client(krb5_context context,

+  }

+  

+  static krb5_error_code

+ -k5_pac_zero_signature(krb5_context context,

+ -                      const krb5_pac pac,

+ -                      krb5_ui_4 type,

+ -                      krb5_data *data)

+ +zero_signature(krb5_context context, const krb5_pac pac, krb5_ui_4 type,

+ +               krb5_data *data)

+  {

+      PAC_INFO_BUFFER *buffer = NULL;

+      size_t i;

+ @@ -530,151 +528,89 @@ k5_pac_zero_signature(krb5_context context,

+  }

+  

+  static krb5_error_code

+ -k5_pac_verify_server_checksum(krb5_context context,

+ -                              const krb5_pac pac,

+ -                              const krb5_keyblock *server)

+ +verify_checksum(krb5_context context, const krb5_pac pac, uint32_t buffer_type,

+ +                const krb5_keyblock *key, krb5_keyusage usage,

+ +                const krb5_data *data)

+  {

+      krb5_error_code ret;

+ -    krb5_data pac_data; /* PAC with zeroed checksums */

+ +    krb5_data buffer;

+ +    krb5_cksumtype cksumtype;

+      krb5_checksum checksum;

+ -    krb5_data checksum_data;

+      krb5_boolean valid;

+ -    krb5_octet *p;

+ +    size_t cksumlen;

+  

+ -    ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,

+ -                               &checksum_data);

+ +    ret = k5_pac_locate_buffer(context, pac, buffer_type, &buffer);

+      if (ret != 0)

+          return ret;

+ -

+ -    if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH)

+ +    if (buffer.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 (checksum.checksum_type == CKSUMTYPE_SHA1)

+ +    cksumtype = load_32_le(buffer.data);

+ +    if (buffer_type == KRB5_PAC_SERVER_CHECKSUM && cksumtype == CKSUMTYPE_SHA1)

+          return KRB5KDC_ERR_SUMTYPE_NOSUPP;

+ -    if (!krb5_c_is_keyed_cksum(checksum.checksum_type))

+ +    if (!krb5_c_is_keyed_cksum(cksumtype))

+          return KRB5KRB_ERR_GENERIC;

+  

+ -    pac_data.length = pac->data.length;

+ -    pac_data.data = k5memdup(pac->data.data, pac->data.length, &ret);

+ -    if (pac_data.data == NULL)

+ -        return ret;

+ -

+ -    /* Zero out both checksum buffers */

+ -    ret = k5_pac_zero_signature(context, pac, KRB5_PAC_SERVER_CHECKSUM,

+ -                                &pac_data);

+ -    if (ret != 0) {

+ -        free(pac_data.data);

+ -        return ret;

+ -    }

+ -

+ -    ret = k5_pac_zero_signature(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,

+ -                                &pac_data);

+ -    if (ret != 0) {

+ -        free(pac_data.data);

+ +    /* There may be an RODCIdentifier trailer (see [MS-PAC] 2.8), so look up

+ +     * the length of the checksum by its type. */

+ +    ret = krb5_c_checksum_length(context, cksumtype, &cksumlen);

+ +    if (ret)

+          return ret;

+ -    }

+ +    if (cksumlen > buffer.length - PAC_SIGNATURE_DATA_LENGTH)

+ +        return KRB5_BAD_MSIZE;

+ +    checksum.checksum_type = cksumtype;

+ +    checksum.length = cksumlen;

+ +    checksum.contents = (uint8_t *)buffer.data + PAC_SIGNATURE_DATA_LENGTH;

+  

+ -    ret = krb5_c_verify_checksum(context, server,

+ -                                 KRB5_KEYUSAGE_APP_DATA_CKSUM,

+ -                                 &pac_data, &checksum, &valid);

+ +    ret = krb5_c_verify_checksum(context, key, usage, data, &checksum, &valid);

+ +    return ret ? ret : (valid ? 0 : KRB5KRB_AP_ERR_MODIFIED);

+ +}

+  

+ -    free(pac_data.data);

+ +static krb5_error_code

+ +verify_server_checksum(krb5_context context, const krb5_pac pac,

+ +                       const krb5_keyblock *server)

+ +{

+ +    krb5_error_code ret;

+ +    krb5_data copy;             /* PAC with zeroed checksums */

+  

+ -    if (ret != 0) {

+ +    ret = krb5int_copy_data_contents(context, &pac->data, &copy);

+ +    if (ret)

+          return ret;

+ -    }

+  

+ -    if (valid == FALSE)

+ -        ret = KRB5KRB_AP_ERR_MODIFIED;

+ +    /* Zero out both checksum buffers */

+ +    ret = zero_signature(context, pac, KRB5_PAC_SERVER_CHECKSUM, &copy);

+ +    if (ret)

+ +        goto cleanup;

+ +    ret = zero_signature(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, &copy);

+ +    if (ret)

+ +        goto cleanup;

+ +

+ +    ret = verify_checksum(context, pac, KRB5_PAC_SERVER_CHECKSUM, server,

+ +                          KRB5_KEYUSAGE_APP_DATA_CKSUM, &copy);

+  

+ +cleanup:

+ +    free(copy.data);

+      return ret;

+  }

+  

+  static krb5_error_code

+ -k5_pac_verify_kdc_checksum(krb5_context context,

+ -                           const krb5_pac pac,

+ -                           const krb5_keyblock *privsvr)

+ +verify_kdc_checksum(krb5_context context, const krb5_pac pac,

+ +                    const krb5_keyblock *privsvr)

+  {

+      krb5_error_code ret;

+ -    krb5_data server_checksum, privsvr_checksum;

+ -    krb5_checksum checksum;

+ -    krb5_boolean valid;

+ -    krb5_octet *p;

+ -

+ -    ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM,

+ -                               &privsvr_checksum);

+ -    if (ret != 0)

+ -        return ret;

+ -

+ -    if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH)

+ -        return KRB5_BAD_MSIZE;

+ +    krb5_data server_checksum;

+  

+      ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_SERVER_CHECKSUM,

+                                 &server_checksum);

+ -    if (ret != 0)

+ +    if (ret)

+          return ret;

+ -

+      if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH)

+          return KRB5_BAD_MSIZE;

+ -

+ -    p = (krb5_octet *)privsvr_checksum.data;

+ -    checksum.checksum_type = load_32_le(p);

+ -    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_ERR_GENERIC;

+ -

+      server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;

+      server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;

+  

+ -    ret = krb5_c_verify_checksum(context, privsvr,

+ -                                 KRB5_KEYUSAGE_APP_DATA_CKSUM,

+ -                                 &server_checksum, &checksum, &valid);

+ -    if (ret != 0)

+ -        return ret;

+ -

+ -    if (valid == FALSE)

+ -        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;

+ +    return verify_checksum(context, pac, KRB5_PAC_PRIVSVR_CHECKSUM, privsvr,

+ +                           KRB5_KEYUSAGE_APP_DATA_CKSUM, &server_checksum);

+  }

+  

+  /* Per MS-PAC 2.8.3, tickets encrypted to TGS and password change principals

+ @@ -761,7 +697,8 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,

+          if (ret)

+              goto cleanup;

+  

+ -        ret = verify_ticket_checksum(context, pac, recoded_tkt, privsvr);

+ +        ret = verify_checksum(context, pac, KRB5_PAC_TICKET_CHECKSUM, privsvr,

+ +                              KRB5_KEYUSAGE_APP_DATA_CKSUM, recoded_tkt);

+          if (ret)

+              goto cleanup;

+      }

+ @@ -804,13 +741,13 @@ krb5_pac_verify_ext(krb5_context context,

+      krb5_error_code ret;

+  

+      if (server != NULL) {

+ -        ret = k5_pac_verify_server_checksum(context, pac, server);

+ +        ret = verify_server_checksum(context, pac, server);

+          if (ret != 0)

+              return ret;

+      }

+  

+      if (privsvr != NULL) {

+ -        ret = k5_pac_verify_kdc_checksum(context, pac, privsvr);

+ +        ret = verify_kdc_checksum(context, pac, privsvr);

+          if (ret != 0)

+              return ret;

+      }

+ -- 

+ 2.39.2

+ 

@@ -0,0 +1,184 @@ 

+ From cd62a504da1457d100ca0e63bd14949dd2e0f3e4 Mon Sep 17 00:00:00 2001

+ From: Greg Hudson <ghudson@mit.edu>

+ Date: Sat, 11 Dec 2021 01:25:34 -0500

+ Subject: [PATCH] Use 14 instead of 9 for unkeyed SHA-1 checksum

+ 

+ Although MIT krb5 had been using the value 9 for unkeyed SHA-1 since

+ its 1.0 release in 1996, RFC 3961 instead assigned this value to

+ rsa-md5-des3 (likely never used), and assigned the values 10 and 14 to

+ SHA-1.  Heimdal and Microsoft use the value 14.  Unkeyed SHA-1 almost

+ never appears on the wire, but has been seen in PKINIT asChecksum

+ fields in replies from Windows KDCs (despite the field being specified

+ as a keyed checksum).

+ 

+ Define a new symbol CKSUMTYPE_SHA1 with the value 14, and use it where

+ we currently use CKSUMTYPE_NIST_SHA.  Continue to allow the value 9

+ for ABI compatibility.  Remove the pkinit_clnt.c workaround as the

+ value 14 will now work without adjustment.

+ 

+ ticket: 9040 (new)

+ ---

+  doc/appdev/refs/macros/index.rst         |  1 +

+  src/include/krb5/krb5.hin                |  6 ++++++

+  src/lib/crypto/crypto_tests/t_cksums.c   |  2 +-

+  src/lib/crypto/krb/cksumtypes.c          |  6 ++++++

+  src/lib/gssapi/mechglue/g_saslname.c     |  3 +--

+  src/lib/krb5/os/trace.c                  |  2 +-

+  src/plugins/kdb/test/kdb_test.c          |  2 +-

+  src/plugins/preauth/pkinit/pkinit_clnt.c | 11 ++---------

+  src/plugins/preauth/pkinit/pkinit_srv.c  |  4 ++--

+  9 files changed, 21 insertions(+), 16 deletions(-)

+ 

+ diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst

+ index 0cb2e81bd7..4bf64e7dfa 100644

+ --- a/doc/appdev/refs/macros/index.rst

+ +++ b/doc/appdev/refs/macros/index.rst

+ @@ -42,6 +42,7 @@ Public

+     CKSUMTYPE_RSA_MD4_DES.rst

+     CKSUMTYPE_RSA_MD5.rst

+     CKSUMTYPE_RSA_MD5_DES.rst

+ +   CKSUMTYPE_SHA1.rst

+     ENCTYPE_AES128_CTS_HMAC_SHA1_96.rst

+     ENCTYPE_AES128_CTS_HMAC_SHA256_128.rst

+     ENCTYPE_AES256_CTS_HMAC_SHA1_96.rst

+ diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin

+ index c26dde535e..f8778075fc 100644

+ --- a/src/include/krb5/krb5.hin

+ +++ b/src/include/krb5/krb5.hin

+ @@ -449,6 +449,11 @@ typedef struct _krb5_crypto_iov {

+  #define ENCTYPE_CAMELLIA256_CTS_CMAC        0x001a /**< RFC 6803 */

+  #define ENCTYPE_UNKNOWN                     0x01ff

+  

+ +/*

+ + * Historically we used the value 9 for unkeyed SHA-1.  RFC 3961 assigns this

+ + * value to rsa-md5-des3, which fortunately is unused.  For ABI compatibility

+ + * we allow either 9 or 14 for SHA-1.

+ + */

+  #define CKSUMTYPE_CRC32         0x0001

+  #define CKSUMTYPE_RSA_MD4       0x0002

+  #define CKSUMTYPE_RSA_MD4_DES   0x0003

+ @@ -459,6 +464,7 @@ typedef struct _krb5_crypto_iov {

+  #define CKSUMTYPE_RSA_MD5_DES   0x0008

+  #define CKSUMTYPE_NIST_SHA      0x0009

+  #define CKSUMTYPE_HMAC_SHA1_DES3      0x000c /* @deprecated removed */

+ +#define CKSUMTYPE_SHA1          0x000d /**< RFC 3962 */

+  #define CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f /**< RFC 3962. Used with

+                                                  ENCTYPE_AES128_CTS_HMAC_SHA1_96 */

+  #define CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010 /**< RFC 3962. Used with

+ diff --git a/src/lib/crypto/crypto_tests/t_cksums.c b/src/lib/crypto/crypto_tests/t_cksums.c

+ index 3063d12ec3..9f9a177ef0 100644

+ --- a/src/lib/crypto/crypto_tests/t_cksums.c

+ +++ b/src/lib/crypto/crypto_tests/t_cksums.c

+ @@ -54,7 +54,7 @@ struct test {

+      },

+      {

+          { KV5M_DATA, 0, "" },

+ -        CKSUMTYPE_NIST_SHA, 0, 0, { KV5M_DATA, 0, "" },

+ +        CKSUMTYPE_SHA1, 0, 0, { KV5M_DATA, 0, "" },

+          { KV5M_DATA, 20,

+            "\xDA\x39\xA3\xEE\x5E\x6B\x4B\x0D\x32\x55\xBF\xEF\x95\x60\x18\x90"

+            "\xAF\xD8\x07\x09" }

+ diff --git a/src/lib/crypto/krb/cksumtypes.c b/src/lib/crypto/krb/cksumtypes.c

+ index f5fbe8a2a7..25a3ffd2d2 100644

+ --- a/src/lib/crypto/krb/cksumtypes.c

+ +++ b/src/lib/crypto/krb/cksumtypes.c

+ @@ -46,6 +46,12 @@ const struct krb5_cksumtypes krb5int_cksumtypes_list[] = {

+        krb5int_unkeyed_checksum, NULL,

+        20, 20, CKSUM_UNKEYED },

+  

+ +    { CKSUMTYPE_SHA1,

+ +      "sha", { 0 }, "SHA-1",

+ +      NULL, &krb5int_hash_sha1,

+ +      krb5int_unkeyed_checksum, NULL,

+ +      20, 20, CKSUM_UNKEYED },

+ +

+      { CKSUMTYPE_HMAC_MD5_ARCFOUR,

+        "hmac-md5-rc4", { "hmac-md5-enc", "hmac-md5-earcfour" },

+        "Microsoft HMAC MD5",

+ diff --git a/src/lib/gssapi/mechglue/g_saslname.c b/src/lib/gssapi/mechglue/g_saslname.c

+ index e25f9e0a53..2be0c8a69a 100644

+ --- a/src/lib/gssapi/mechglue/g_saslname.c

+ +++ b/src/lib/gssapi/mechglue/g_saslname.c

+ @@ -58,8 +58,7 @@ oidToSaslName(OM_uint32 *minor, const gss_OID mech,

+      iov[2].data.length = sizeof(cksumBuf);

+      iov[2].data.data = (char *)cksumBuf;

+  

+ -    *minor = krb5_k_make_checksum_iov(NULL, CKSUMTYPE_NIST_SHA,

+ -                                      NULL, 0, iov, 3);

+ +    *minor = krb5_k_make_checksum_iov(NULL, CKSUMTYPE_SHA1, NULL, 0, iov, 3);

+      if (*minor != 0)

+          return GSS_S_FAILURE;

+  

+ diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c

+ index e9b99f4ca0..abb8a3f21b 100644

+ --- a/src/lib/krb5/os/trace.c

+ +++ b/src/lib/krb5/os/trace.c

+ @@ -93,7 +93,7 @@ hash_bytes(krb5_context context, const void *ptr, size_t len)

+      krb5_data d = make_data((void *) ptr, len);

+      char *s = NULL;

+  

+ -    if (krb5_k_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0, &d,

+ +    if (krb5_k_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, &d,

+                               &cksum) != 0)

+          return NULL;

+      if (cksum.length >= 2)

+ diff --git a/src/plugins/kdb/test/kdb_test.c b/src/plugins/kdb/test/kdb_test.c

+ index 2138abc767..2e02e2141f 100644

+ --- a/src/plugins/kdb/test/kdb_test.c

+ +++ b/src/plugins/kdb/test/kdb_test.c

+ @@ -205,7 +205,7 @@ make_keyblock(krb5_kvno kvno, krb5_enctype etype, int32_t salttype,

+                   (int)salttype, princstr, (int)realm->length, realm->data) < 0)

+          abort();

+      d = string2data(hashstr);

+ -    check(krb5_c_make_checksum(NULL, CKSUMTYPE_NIST_SHA, NULL, 0, &d, &cksum));

+ +    check(krb5_c_make_checksum(NULL, CKSUMTYPE_SHA1, NULL, 0, &d, &cksum));

+  

+      /* Make the appropriate number of input bytes from the hash result. */

+      for (pos = 0; pos < keybytes; pos += n) {

+ diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c

+ index a385da7c3d..f8c0d7150a 100644

+ --- a/src/plugins/preauth/pkinit/pkinit_clnt.c

+ +++ b/src/plugins/preauth/pkinit/pkinit_clnt.c

+ @@ -119,8 +119,8 @@ pa_pkinit_gen_req(krb5_context context,

+          goto cleanup;

+      }

+  

+ -    retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0,

+ -                                  der_req, &cksum);

+ +    retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,

+ +                                  &cksum);

+      if (retval)

+          goto cleanup;

+      TRACE_PKINIT_CLIENT_REQ_CHECKSUM(context, &cksum);

+ @@ -701,13 +701,6 @@ pkinit_as_rep_parse(krb5_context context,

+              pkiDebug("failed to decode reply_key_pack\n");

+              goto cleanup;

+          }

+ -        /*

+ -         * This is hack but Windows sends back SHA1 checksum

+ -         * with checksum type of 14. There is currently no

+ -         * checksum type of 14 defined.

+ -         */

+ -        if (key_pack->asChecksum.checksum_type == 14)

+ -            key_pack->asChecksum.checksum_type = CKSUMTYPE_NIST_SHA;

+          retval = krb5_c_make_checksum(context,

+                                        key_pack->asChecksum.checksum_type,

+                                        &key_pack->replyKey,

+ diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c

+ index 3ae56c0641..3bff456f8f 100644

+ --- a/src/plugins/preauth/pkinit/pkinit_srv.c

+ +++ b/src/plugins/preauth/pkinit/pkinit_srv.c

+ @@ -546,8 +546,8 @@ pkinit_server_verify_padata(krb5_context context,

+          goto cleanup;

+      }

+      der_req = cb->request_body(context, rock);

+ -    retval = krb5_c_make_checksum(context, CKSUMTYPE_NIST_SHA, NULL, 0,

+ -                                  der_req, &cksum);

+ +    retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,

+ +                                  &cksum);

+      if (retval) {

+          pkiDebug("unable to calculate AS REQ checksum\n");

+          goto cleanup;

+ -- 

+ 2.39.2

+ 

@@ -0,0 +1,186 @@ 

+ From bb7d0bacde34434ec6a5f4243e0936072e18d12c Mon Sep 17 00:00:00 2001

+ From: Julien Rische <jrische@redhat.com>

+ Date: Mon, 3 Jul 2023 11:41:28 +0200

+ Subject: [PATCH] [downstream] Backport PAC indicator test facility

+ 

+ Partial backport of upstream 78fd66926c4be5910c1e21d9e553dfb792ae822a

+ ---

+  src/tests/adata.c | 100 +++++++++++++++++++++++++---------------------

+  1 file changed, 55 insertions(+), 45 deletions(-)

+ 

+ diff --git a/src/tests/adata.c b/src/tests/adata.c

+ index 3869aec1d5..58981c9711 100644

+ --- a/src/tests/adata.c

+ +++ b/src/tests/adata.c

+ @@ -55,9 +55,10 @@

+  

+  static krb5_context ctx;

+  

+ -static void display_authdata_list(krb5_authdata **list, krb5_keyblock *skey,

+ +static void display_authdata_list(krb5_authdata **list,

+ +                                  krb5_enc_tkt_part *enc_tkt,

+                                    krb5_keyblock *tktkey, char prefix_byte,

+ -                                  krb5_boolean pac_expected);

+ +                                  krb5_boolean pac_ok);

+  

+  static void

+  check(krb5_error_code code)

+ @@ -165,6 +166,43 @@ get_container_contents(krb5_authdata *ad, krb5_keyblock *skey,

+      return inner_ad;

+  }

+  

+ +static int

+ +compare_uint32(const void *p1, const void *p2)

+ +{

+ +    uint32_t t1 = *(uint32_t *)p1, t2 = *(uint32_t *)p2;

+ +

+ +    return (t1 > t2) ? 1 : (t1 == t2) ? 0 : -1;

+ +}

+ +

+ +static void

+ +display_pac(krb5_authdata *ad, krb5_enc_tkt_part *enc_tkt,

+ +            krb5_keyblock *tktkey)

+ +{

+ +    krb5_pac pac;

+ +    size_t tlen, i;

+ +    uint32_t *types;

+ +

+ +    assert(ad->ad_type == KRB5_AUTHDATA_WIN2K_PAC);

+ +    check(krb5_pac_parse(ctx, ad->contents, ad->length, &pac));

+ +

+ +    check(krb5_pac_verify(ctx, pac, enc_tkt->times.authtime, enc_tkt->client,

+ +                          tktkey, NULL));

+ +

+ +    check(krb5_pac_get_types(ctx, pac, &tlen, &types));

+ +    qsort(types, tlen, sizeof(*types), compare_uint32);

+ +

+ +    printf("[");

+ +    for (i = 0; i < tlen; i++) {

+ +        printf("%d", (int)types[i]);

+ +        if (i + 1 < tlen)

+ +            printf(", ");

+ +    }

+ +    printf("]");

+ +

+ +    free(types);

+ +    krb5_pac_free(ctx, pac);

+ +}

+ +

+  /* Decode and display authentication indicator authdata. */

+  static void

+  display_auth_indicator(krb5_authdata *ad)

+ @@ -206,8 +244,8 @@ display_binary_or_ascii(krb5_authdata *ad)

+  /* Display the contents of an authdata element, prefixed by prefix_byte.  skey

+   * must be the ticket session key. */

+  static void

+ -display_authdata(krb5_authdata *ad, krb5_keyblock *skey, krb5_keyblock *tktkey,

+ -                 int prefix_byte, krb5_boolean pac_expected)

+ +display_authdata(krb5_authdata *ad, krb5_enc_tkt_part *enc_tkt,

+ +                 krb5_keyblock *tktkey, int prefix_byte, krb5_boolean pac_ok)

+  {

+      krb5_authdata **inner_ad;

+  

+ @@ -216,21 +254,23 @@ display_authdata(krb5_authdata *ad, krb5_keyblock *skey, krb5_keyblock *tktkey,

+          ad->ad_type == KRB5_AUTHDATA_KDC_ISSUED ||

+          ad->ad_type == KRB5_AUTHDATA_CAMMAC) {

+          if (ad->ad_type != KRB5_AUTHDATA_IF_RELEVANT)

+ -            pac_expected = FALSE;

+ +            pac_ok = FALSE;

+          /* Decode and display the contents. */

+ -        inner_ad = get_container_contents(ad, skey, tktkey);

+ -        display_authdata_list(inner_ad, skey, tktkey, get_prefix_byte(ad),

+ -                              pac_expected);

+ +        inner_ad = get_container_contents(ad, enc_tkt->session, tktkey);

+ +        display_authdata_list(inner_ad, enc_tkt, tktkey, get_prefix_byte(ad),

+ +                              pac_ok);

+          krb5_free_authdata(ctx, inner_ad);

+          return;

+      }

+  

+ -    assert(!pac_expected || ad->ad_type == KRB5_AUTHDATA_WIN2K_PAC);

+ +    assert(pac_ok || ad->ad_type != KRB5_AUTHDATA_WIN2K_PAC);

+  

+      printf("%c", prefix_byte);

+      printf("%d: ", (int)ad->ad_type);

+  

+ -    if (ad->ad_type == KRB5_AUTHDATA_AUTH_INDICATOR)

+ +    if (ad->ad_type == KRB5_AUTHDATA_WIN2K_PAC)

+ +        display_pac(ad, enc_tkt, tktkey);

+ +    else if (ad->ad_type == KRB5_AUTHDATA_AUTH_INDICATOR)

+          display_auth_indicator(ad);

+      else

+          display_binary_or_ascii(ad);

+ @@ -238,46 +278,19 @@ display_authdata(krb5_authdata *ad, krb5_keyblock *skey, krb5_keyblock *tktkey,

+  }

+  

+  static void

+ -display_authdata_list(krb5_authdata **list, krb5_keyblock *skey,

+ +display_authdata_list(krb5_authdata **list, krb5_enc_tkt_part *tkt_enc,

+                        krb5_keyblock *tktkey, char prefix_byte,

+ -                      krb5_boolean pac_expected)

+ +                      krb5_boolean pac_ok)

+  {

+      if (list == NULL)

+          return;

+      /* Only expect a PAC in the first element, if at all. */

+      for (; *list != NULL; list++) {

+ -        display_authdata(*list, skey, tktkey, prefix_byte, pac_expected);

+ -        pac_expected = FALSE;

+ +        display_authdata(*list, tkt_enc, tktkey, prefix_byte, pac_ok);

+ +        pac_ok = FALSE;

+      }

+  }

+  

+ -/* If a PAC is present in enc_part2, verify its service signature with key and

+ - * set *has_pac to true. */

+ -static void

+ -check_pac(krb5_context context, krb5_enc_tkt_part *enc_part2,

+ -          const krb5_keyblock *key, krb5_boolean *has_pac)

+ -{

+ -    krb5_authdata **authdata;

+ -    krb5_pac pac;

+ -

+ -    *has_pac = FALSE;

+ -

+ -    check(krb5_find_authdata(context, enc_part2->authorization_data, NULL,

+ -                             KRB5_AUTHDATA_WIN2K_PAC, &authdata));

+ -    if (authdata == NULL)

+ -        return;

+ -

+ -    assert(authdata[1] == NULL);

+ -    check(krb5_pac_parse(context, authdata[0]->contents, authdata[0]->length,

+ -                         &pac));

+ -    krb5_free_authdata(context, authdata);

+ -

+ -    check(krb5_pac_verify(context, pac, enc_part2->times.authtime,

+ -                          enc_part2->client, key, NULL));

+ -    krb5_pac_free(context, pac);

+ -    *has_pac = TRUE;

+ -}

+ -

+  int

+  main(int argc, char **argv)

+  {

+ @@ -289,7 +302,6 @@ main(int argc, char **argv)

+      krb5_ticket *ticket;

+      krb5_authdata **req_authdata = NULL, *ad;

+      krb5_keytab_entry ktent;

+ -    krb5_boolean with_pac;

+      size_t count;

+      int c;

+  

+ @@ -349,10 +361,8 @@ main(int argc, char **argv)

+                              ticket->enc_part.enctype, &ktent));

+      check(krb5_decrypt_tkt_part(ctx, &ktent.key, ticket));

+  

+ -    check_pac(ctx, ticket->enc_part2, &ktent.key, &with_pac);

+      display_authdata_list(ticket->enc_part2->authorization_data,

+ -                          ticket->enc_part2->session, &ktent.key, ' ',

+ -                          with_pac);

+ +                          ticket->enc_part2, &ktent.key, ' ', TRUE);

+  

+      while (count > 0) {

+          free(req_authdata[--count]->contents);

+ -- 

+ 2.41.0

+ 

@@ -0,0 +1,93 @@ 

+ From 8fa5b4a7925cc5951900db98322f5f0c1d03796e Mon Sep 17 00:00:00 2001

+ From: Julien Rische <jrische@redhat.com>

+ Date: Tue, 28 Mar 2023 10:31:50 +0200

+ Subject: [PATCH] [downstream] Remove deprecated SELinux context type

+ 

+ ---

+  src/util/support/selinux.c | 23 +++++++++++------------

+  1 file changed, 11 insertions(+), 12 deletions(-)

+ 

+ diff --git a/src/util/support/selinux.c b/src/util/support/selinux.c

+ index 6d41f3244f..807d039da3 100644

+ --- a/src/util/support/selinux.c

+ +++ b/src/util/support/selinux.c

+ @@ -96,17 +96,16 @@ cleanup_fscreatecon(void)

+      }

+  }

+  

+ -static security_context_t

+ +static char *

+  push_fscreatecon(const char *pathname, mode_t mode)

+  {

+ -    security_context_t previous, configuredsc, currentsc, derivedsc;

+ +    char *previous, *configuredsc, *currentsc, *genpath;

+ +    const char *derivedsc, *fullpath, *currentuser;

+      context_t current, derived;

+ -    const char *fullpath, *currentuser;

+ -    char *genpath;

+  

+ -    previous = configuredsc = currentsc = derivedsc = NULL;

+ +    previous = configuredsc = currentsc = genpath = NULL;

+ +    derivedsc = NULL;

+      current = derived = NULL;

+ -    genpath = NULL;

+  

+      fullpath = pathname;

+  

+ @@ -234,7 +233,7 @@ fail:

+  }

+  

+  static void

+ -pop_fscreatecon(security_context_t previous)

+ +pop_fscreatecon(char *previous)

+  {

+      if (!is_selinux_enabled()) {

+          return;

+ @@ -288,7 +287,7 @@ krb5int_labeled_fopen(const char *path, const char *mode)

+  {

+      FILE *fp;

+      int errno_save;

+ -    security_context_t ctx;

+ +    char *ctx;

+  

+      if ((strcmp(mode, "r") == 0) ||

+          (strcmp(mode, "rb") == 0)) {

+ @@ -314,7 +313,7 @@ krb5int_labeled_creat(const char *path, mode_t mode)

+  {

+      int fd;

+      int errno_save;

+ -    security_context_t ctx;

+ +    char *ctx;

+  

+      k5_once(&labeled_once, label_mutex_init);

+      k5_mutex_lock(&labeled_mutex);

+ @@ -335,7 +334,7 @@ krb5int_labeled_mknod(const char *path, mode_t mode, dev_t dev)

+  {

+      int ret;

+      int errno_save;

+ -    security_context_t ctx;

+ +    char *ctx;

+  

+      k5_once(&labeled_once, label_mutex_init);

+      k5_mutex_lock(&labeled_mutex);

+ @@ -356,7 +355,7 @@ krb5int_labeled_mkdir(const char *path, mode_t mode)

+  {

+      int ret;

+      int errno_save;

+ -    security_context_t ctx;

+ +    char *ctx;

+  

+      k5_once(&labeled_once, label_mutex_init);

+      k5_mutex_lock(&labeled_mutex);

+ @@ -377,7 +376,7 @@ krb5int_labeled_open(const char *path, int flags, ...)

+  {

+      int fd;

+      int errno_save;

+ -    security_context_t ctx;

+ +    char *ctx;

+      mode_t mode;

+      va_list ap;

+  

+ -- 

+ 2.41.0

+ 

@@ -0,0 +1,163 @@ 

+ From fb162383e00a28ed6b23d455ef6b1f1010e7dadd Mon Sep 17 00:00:00 2001

+ From: Julien Rische <jrische@redhat.com>

+ Date: Fri, 24 Mar 2023 16:22:06 +0100

+ Subject: [PATCH] [downstream] Support PAC full checksum w/o ticket checksum

+ 

+ ---

+  doc/appdev/refs/api/index.rst |  1 +

+  src/include/krb5/krb5.hin     | 38 +++++++++++++++++++++++++++++++++++

+  src/lib/krb5/krb/pac.c        | 10 ++++++++-

+  src/lib/krb5/krb/pac_sign.c   | 17 ++++++++++++++++

+  src/lib/krb5/libkrb5.exports  |  1 +

+  src/tests/t_authdata.py       |  4 ++--

+  6 files changed, 68 insertions(+), 3 deletions(-)

+ 

+ diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst

+ index d12be47c3c..ff813108bb 100644

+ --- a/doc/appdev/refs/api/index.rst

+ +++ b/doc/appdev/refs/api/index.rst

+ @@ -248,6 +248,7 @@ Rarely used public interfaces

+     krb5_os_localaddr.rst

+     krb5_pac_add_buffer.rst

+     krb5_pac_free.rst

+ +   krb5_pac_full_sign_compat.rst

+     krb5_pac_get_buffer.rst

+     krb5_pac_get_types.rst

+     krb5_pac_init.rst

+ diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin

+ index 61c7ea985d..b3f05dd047 100644

+ --- a/src/include/krb5/krb5.hin

+ +++ b/src/include/krb5/krb5.hin

+ @@ -8397,6 +8397,44 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,

+                    const krb5_keyblock *privsvr_key, krb5_boolean with_realm,

+                    krb5_data *data);

+  

+ +/**

+ + * Compatibility function used by IPA if the 1.20 KDB diver API is not

+ + * available.  It generates PAC signatures, including the extended KDC one when

+ + * relevant.

+ + *

+ + * It is similar to krb5_kdc_sign_ticket(), except it will not generate the

+ + * PAC ticket signature, and therefore does not expect encrypted ticket part as

+ + * parameter.

+ + *

+ + * @param [in]  context         Library context

+ + * @param [in]  pac             PAC handle

+ + * @param [in]  authtime        Expected timestamp

+ + * @param [in]  client_princ    Client principal name (or NULL)

+ + * @param [in]  server_princ    Server principal name

+ + * @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 client_princ

+ + * @param [out] data            Signed PAC encoding

+ + *

+ + * 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 with_realm is true, the PAC_CLIENT_INFO field of the signed PAC will

+ + * include the realm of @a client_princ as well as the name.  This flag is

+ + * necessary to generate PACs for cross-realm S4U2Self referrals.

+ + */

+ +krb5_error_code KRB5_CALLCONV

+ +krb5_pac_full_sign_compat(krb5_context context, krb5_pac pac,

+ +                          krb5_timestamp authtime,

+ +                          krb5_const_principal client_princ,

+ +                          krb5_const_principal server_princ,

+ +                          const krb5_keyblock *server_key,

+ +                          const krb5_keyblock *privsvr_key,

+ +                          krb5_boolean with_realm,

+ +                          krb5_data *data);

+ +

+  /**

+   * Sign a PAC, possibly including a ticket signature

+   *

+ diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c

+ index 9c00178a28..b7fa064100 100644

+ --- a/src/lib/krb5/krb/pac.c

+ +++ b/src/lib/krb5/krb/pac.c

+ @@ -757,9 +757,17 @@ krb5_pac_verify_ext(krb5_context context,

+                      krb5_boolean with_realm)

+  {

+      krb5_error_code ret;

+ +    krb5_boolean has_full_chksum;

+  

+      if (server != NULL || privsvr != NULL) {

+ -        ret = verify_pac_checksums(context, pac, FALSE, server, privsvr);

+ +        /* Fail only if full checksum is present and invalid.

+ +         * Proceed if absent.

+ +         */

+ +        ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_FULL_CHECKSUM, NULL);

+ +        has_full_chksum = ret != ENOENT;

+ +

+ +        ret = verify_pac_checksums(context, pac, has_full_chksum, server,

+ +                                   privsvr);

+          if (ret != 0)

+              return ret;

+      }

+ diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c

+ index 8ea61ac17b..7c3a86d8eb 100644

+ --- a/src/lib/krb5/krb/pac_sign.c

+ +++ b/src/lib/krb5/krb/pac_sign.c

+ @@ -309,6 +309,23 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,

+                      with_realm, FALSE, data);

+  }

+  

+ +krb5_error_code KRB5_CALLCONV

+ +krb5_pac_full_sign_compat(krb5_context context, krb5_pac pac,

+ +                          krb5_timestamp authtime,

+ +                          krb5_const_principal client_princ,

+ +                          krb5_const_principal server_princ,

+ +                          const krb5_keyblock *server_key,

+ +                          const krb5_keyblock *privsvr_key,

+ +                          krb5_boolean with_realm,

+ +                          krb5_data *data)

+ +{

+ +    krb5_boolean is_service_tkt;

+ +

+ +    is_service_tkt = k5_pac_should_have_ticket_signature(server_princ);

+ +    return sign_pac(context, pac, authtime, client_princ, server_key,

+ +                    privsvr_key, with_realm, is_service_tkt, data);

+ +}

+ +

+  /* 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

+ diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports

+ index 0ff4f191d6..d48630ccc6 100644

+ --- a/src/lib/krb5/libkrb5.exports

+ +++ b/src/lib/krb5/libkrb5.exports

+ @@ -510,6 +510,7 @@ krb5_os_localaddr

+  krb5_overridekeyname

+  krb5_pac_add_buffer

+  krb5_pac_free

+ +krb5_pac_full_sign_compat

+  krb5_pac_get_buffer

+  krb5_pac_get_types

+  krb5_pac_init

+ diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py

+ index be3eaf7668..2ceca4838d 100644

+ --- a/src/tests/t_authdata.py

+ +++ b/src/tests/t_authdata.py

+ @@ -11,7 +11,7 @@ realm = K5Realm(krb5_conf=conf)

+  # container.

+  mark('baseline authdata')

+  out = realm.run(['./adata', realm.host_princ])

+ -if '?128: [6, 7, 10, 16, 19]' not in out or '^-42: Hello' not in out:

+ +if '?512:' not in out or '^-42: Hello' not in out:

+      fail('expected authdata not seen for basic request')

+  

+  # Requested authdata is copied into the ticket, with KDC-only types

+ @@ -240,7 +240,7 @@ out = realm.run(['./adata', '-p', realm.user_princ, 'service/2'])

+  if '+97: [indcl]' not in out or '[inds1]' in out:

+      fail('correct auth-indicator not seen for S4U2Proxy req')

+  # Make sure a PAC with an S4U_DELEGATION_INFO(11) buffer is included.

+ -if '?128: [1, 6, 7, 10, 11, 16, 19]' not in out:

+ +if '?128: [1, 6, 7, 10, 11]' not in out:

+      fail('PAC with delegation info not seen for S4U2Proxy req')

+  

+  # Get another S4U2Proxy ticket including request-authdata.

+ -- 

+ 2.41.0

+ 

file modified
+13 -1
@@ -34,7 +34,7 @@ 

  #

  # baserelease is what we have standardized across Fedora and what

  # rpmdev-bumpspec knows how to handle.

- %global baserelease 13

+ %global baserelease 14

  

  # This should be e.g. beta1 or %%nil

  %global pre_release %nil
@@ -121,6 +121,13 @@ 

  Patch42: downstream-Allow-krad-UDP-TCP-localhost-connection-with-FIPS.patch

  Patch43: Read-GSS-configuration-files-with-mtime-0.patch

  Patch44: Fix-integer-overflows-in-PAC-parsing.patch

+ Patch45: Use-14-instead-of-9-for-unkeyed-SHA-1-checksum.patch

+ Patch46: Add-PAC-ticket-signature-APIs.patch

+ Patch47: Factor-out-PAC-checksum-verification.patch

+ Patch48: Add-PAC-full-checksums.patch

+ Patch49: downstream-Support-PAC-full-checksum-w-o-ticket-chec.patch

+ Patch50: downstream-Remove-deprecated-SELinux-context-type.patch

+ Patch51: downstream-Backport-PAC-indicator-test-facility.patch

  

  License: MIT

  URL: https://web.mit.edu/kerberos/www/
@@ -676,6 +683,11 @@ 

  %{_libdir}/libkadm5srv_mit.so.*

  

  %changelog

+ * Fri Jun 30 2023 Julien Rische <jrische@redhat.com> - 1.19.2-14

+ - Add krb5_pac_full_sign_compat() function generating PAC extended KDC signature

+ - Resolves: rhbz#2182135

+ - Remove deprecated SELinux context data type

+ 

  * Wed Nov 09 2022 Julien Rische <jrische@redhat.com> - 1.19.2-13

  - Fix integer overflows in PAC parsing (CVE-2022-42898)

  - Resolves: rhbz#2143011

  • Add krb5_pac_full_sign_compat() function generating PAC extended KDC signature
  • Remove deprecated SELinux context data type

Resolves: rhbz#2182135

Metadata Update from @jrische:
- Request assigned

11 months ago

rebased onto e4487abb015bdca730f5ae1b725bd5e138591512

11 months ago

rebased onto 89c733d

10 months ago

This backport is canceled because it won't bring any direct benefits. Please see the associated bugzilla for details.

Pull-Request has been closed by jrische

9 months ago