#
# We expect all the MIT specific compatability tests to fail on heimdal
# kerberos
-^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_mit_(?!ticket_signature)
+^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_mit_
#
# Heimdal currently fails the following MS-KILE client principal lookup
# tests
^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_tgs_outer_no_sname.ad_dc
^samba.tests.krb5.fast_tests.samba.tests.krb5.fast_tests.FAST_Tests.test_fast_no_sname.ad_dc
#
-# Heimdal currently does not generate ticket signatures
-#
-^samba.tests.krb5.compatability_tests.samba.tests.krb5.compatability_tests.SimpleKerberosTests.test_heimdal_ticket_signature
-#
# S4U tests
#
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_rbcd_old_checksum
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_missing_client_checksum
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_no_service_pac
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_client_checksum
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_unkeyed_service_checksum
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_unkeyed_service_checksum
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_client_checksum
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_zeroed_service_checksum
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_client_not_delegated
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_forwardable
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_forwardable
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_trusted_empty_allowed
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_not_trusted_nonempty_allowed
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_trusted_empty_allowed
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_trusted_nonempty_allowed
-^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_s4u2self_without_forwardable
#
# RODC tests
#
^samba.tests.krb5.rodc_tests.samba.tests.krb5.rodc_tests.RodcKerberosTests.test_rodc_ticket_signature
#
-# PAC tests
-#
-^netr-bdc-arcfour.verify-sig-arcfour
-^netr-bdc-arcfour.verify-sig-arcfour
-^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc:local
-^samba4.blackbox.pkinit_pac.STEP1 remote.pac verification.ad_dc_ntvfs:local
-^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc:local
-^samba4.blackbox.pkinit_pac.netr-bdc-aes.verify-sig-aes.ad_dc_ntvfs:local
-^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc:local
-^samba4.blackbox.pkinit_pac.netr-mem-aes.s4u2proxy-aes.ad_dc_ntvfs:local
-^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc:local
-^samba4.blackbox.pkinit_pac.netr-mem-aes.verify-sig-aes.ad_dc_ntvfs:local
-^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc:local
-^samba4.blackbox.pkinit_pac.netr-mem-arcfour.s4u2proxy-arcfour.ad_dc_ntvfs:local
-^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc:local
-^samba4.blackbox.pkinit_pac.netr-mem-arcfour.verify-sig-arcfour.ad_dc_ntvfs:local
-^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2000dc
-^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2003dc
-^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008dc
-^samba4.rpc.pac on ncacn_np.netr-bdc-aes.verify-sig-aes.fl2008r2dc
-^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2000dc
-^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2003dc
-^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008dc
-^samba4.rpc.pac on ncacn_np.netr-bdc-arcfour.verify-sig-arcfour.fl2008r2dc
-^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2000dc
-^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2003dc
-^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008dc
-^samba4.rpc.pac on ncacn_np.netr-mem-aes.s4u2proxy-aes.fl2008r2dc
-^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2000dc
-^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2003dc
-^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008dc
-^samba4.rpc.pac on ncacn_np.netr-mem-aes.verify-sig-aes.fl2008r2dc
-^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2000dc
-^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2003dc
-^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008dc
-^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.s4u2proxy-arcfour.fl2008r2dc
-^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2000dc
-^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2003dc
-^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008dc
-^samba4.rpc.pac on ncacn_np.netr-mem-arcfour.verify-sig-arcfour.fl2008r2dc
-#
# The lack of KRB5SignedPath means we no longer return
# KRB5KRB_ERR_RESPONSE_TOO_BIG in this specific case
#
if (send_pac_p(context, req)) {
krb5_pac p = NULL;
krb5_data data;
+ uint16_t rodc_id;
ret = _kdc_pac_generate(context, client, pk_reply_key, &p);
if (ret) {
goto out;
}
if (p != NULL) {
+ rodc_id = server->entry.kvno >> 16;
+
ret = _krb5_pac_sign(context, p, et.authtime,
client->entry.principal,
&skey->key, /* Server key */
&skey->key, /* FIXME: should be krbtgt key */
+ rodc_id,
&data);
krb5_pac_free(context, p);
if (ret) {
goto out;
}
- ret = _kdc_tkt_add_if_relevant_ad(context, &et,
- KRB5_AUTHDATA_WIN2K_PAC,
- &data);
+ ret = _kdc_tkt_insert_pac(context, &et, &data);
krb5_data_free(&data);
if (ret)
goto out;
return TRUE;
}
-
-/*
- * Add the AuthorizationData `data´ of `type´ to the last element in
- * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT
- */
-
-krb5_error_code
-_kdc_tkt_add_if_relevant_ad(krb5_context context,
- EncTicketPart *tkt,
- int type,
- const krb5_data *data)
-{
- krb5_error_code ret;
- size_t size = 0;
-
- if (tkt->authorization_data == NULL) {
- tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
- if (tkt->authorization_data == NULL) {
- krb5_set_error_message(context, ENOMEM, "out of memory");
- return ENOMEM;
- }
- }
-
- /* add the entry to the last element */
- {
- AuthorizationData ad = { 0, NULL };
- AuthorizationDataElement ade;
-
- ade.ad_type = type;
- ade.ad_data = *data;
-
- ret = add_AuthorizationData(&ad, &ade);
- if (ret) {
- krb5_set_error_message(context, ret, "add AuthorizationData failed");
- return ret;
- }
-
- ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
-
- ASN1_MALLOC_ENCODE(AuthorizationData,
- ade.ad_data.data, ade.ad_data.length,
- &ad, &size, ret);
- free_AuthorizationData(&ad);
- if (ret) {
- krb5_set_error_message(context, ret, "ASN.1 encode of "
- "AuthorizationData failed");
- return ret;
- }
- if (ade.ad_data.length != size)
- krb5_abortx(context, "internal asn.1 encoder error");
-
- ret = add_AuthorizationData(tkt->authorization_data, &ade);
- der_free_octet_string(&ade.ad_data);
- if (ret) {
- krb5_set_error_message(context, ret, "add AuthorizationData failed");
- return ret;
- }
- }
-
- return 0;
-}
hdb_entry_ex *client,
hdb_entry_ex *server,
hdb_entry_ex *krbtgt,
+ hdb_entry_ex *ticket_server,
const EncryptionKey *server_check_key,
- const EncryptionKey *server_sign_key,
- const EncryptionKey *krbtgt_sign_key,
+ const EncryptionKey *krbtgt_check_key,
EncTicketPart *tkt,
- krb5_data *rspac,
- int *signedpath)
+ krb5_boolean *kdc_issued,
+ krb5_pac *ppac)
{
- AuthorizationData *ad = tkt->authorization_data;
- unsigned i, j;
+ krb5_pac pac = NULL;
krb5_error_code ret;
+ krb5_boolean signedticket;
- if (ad == NULL || ad->len == 0)
- return 0;
-
- for (i = 0; i < ad->len; i++) {
- AuthorizationData child;
-
- if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
- continue;
-
- ret = decode_AuthorizationData(ad->val[i].ad_data.data,
- ad->val[i].ad_data.length,
- &child,
- NULL);
- if (ret) {
- krb5_set_error_message(context, ret, "Failed to decode "
- "IF_RELEVANT with %d", ret);
- return ret;
- }
- for (j = 0; j < child.len; j++) {
-
- if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
- int signed_pac = 0;
- krb5_pac pac;
-
- /* Found PAC */
- ret = krb5_pac_parse(context,
- child.val[j].ad_data.data,
- child.val[j].ad_data.length,
- &pac);
- free_AuthorizationData(&child);
- if (ret)
- return ret;
+ *kdc_issued = FALSE;
+ *ppac = NULL;
- ret = krb5_pac_verify(context, pac, tkt->authtime,
- client_principal,
- server_check_key, NULL);
- if (ret) {
- krb5_pac_free(context, pac);
- return ret;
- }
+ ret = _krb5_kdc_pac_ticket_parse(context, tkt, &signedticket, &pac);
+ if (ret || pac == NULL)
+ return ret;
- ret = _kdc_pac_verify(context, client_principal,
- delegated_proxy_principal,
- client, server, krbtgt, &pac, &signed_pac);
- if (ret) {
- krb5_pac_free(context, pac);
- return ret;
- }
+ /* Verify the server signature. */
+ ret = krb5_pac_verify(context, pac, tkt->authtime, client_principal,
+ server_check_key, NULL);
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
- /*
- * Only re-sign PAC if we could verify it with the PAC
- * function. The no-verify case happens when we get in
- * a PAC from cross realm from a Windows domain and
- * that there is no PAC verification function.
- */
- if (signed_pac) {
- *signedpath = 1;
- ret = _krb5_pac_sign(context, pac, tkt->authtime,
- client_principal,
- server_sign_key, krbtgt_sign_key, rspac);
- }
+ /* Verify the KDC signatures. */
+ ret = _kdc_pac_verify(context, client_principal, delegated_proxy_principal,
+ client, server, krbtgt, &pac);
+ if (ret == KRB5_PLUGIN_NO_HANDLE) {
+ /*
+ * We can't verify the KDC signatures if the ticket was issued by
+ * another realm's KDC.
+ */
+ if (krb5_realm_compare(context, server->entry.principal,
+ ticket_server->entry.principal)) {
+ ret = krb5_pac_verify(context, pac, 0, NULL, NULL,
+ krbtgt_check_key);
+ if (ret) {
krb5_pac_free(context, pac);
-
return ret;
}
}
- free_AuthorizationData(&child);
+ /* Discard the PAC if the plugin didn't handle it */
+ krb5_pac_free(context, pac);
+ ret = krb5_pac_init(context, &pac);
+ if (ret)
+ return ret;
+ } else if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
}
+
+ *kdc_issued = signedticket ||
+ krb5_principal_is_krbtgt(context,
+ ticket_server->entry.principal);
+ *ppac = pac;
+
return 0;
}
tgs_make_reply(krb5_context context,
krb5_kdc_configuration *config,
KDC_REQ_BODY *b,
- krb5_const_principal tgt_name,
+ krb5_principal tgt_name,
const EncTicketPart *tgt,
const krb5_keyblock *replykey,
int rk_is_subkey,
const EncryptionKey *serverkey,
+ const EncryptionKey *krbtgtkey,
const krb5_keyblock *sessionkey,
krb5_kvno kvno,
AuthorizationData *auth_data,
hdb_entry_ex *client,
krb5_principal client_principal,
hdb_entry_ex *krbtgt,
- krb5_enctype krbtgt_etype,
- const krb5_data *rspac,
+ krb5_pac mspac,
+ uint16_t rodc_id,
+ krb5_boolean add_ticket_sig,
const METHOD_DATA *enc_pa_data,
const char **e_text,
krb5_data *reply)
if (!server->entry.flags.proxiable)
et.flags.proxiable = 0;
- if(rspac->length) {
- /*
- * No not need to filter out the any PAC from the
- * auth_data since it's signed by the KDC.
- */
- ret = _kdc_tkt_add_if_relevant_ad(context, &et,
- KRB5_AUTHDATA_WIN2K_PAC, rspac);
- if (ret)
- goto out;
- }
-
if (auth_data) {
unsigned int i = 0;
is_weak = 1;
}
+ /* The PAC should be the last change to the ticket. */
+ ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey,
+ krbtgtkey, rodc_id, add_ticket_sig, &et);
+ if (ret)
+ goto out;
/* It is somewhat unclear where the etype in the following
encryption should come from. What we have is a session
int **cusec,
AuthorizationData **auth_data,
krb5_keyblock **replykey,
+ Key **header_key,
int *rk_is_subkey)
{
static char failed[] = "<unparse_name failed>";
goto out;
}
+ *header_key = tkey;
+
{
krb5_authenticator auth;
return ENOMEM;
}
+static krb5_error_code
+db_fetch_client(krb5_context context,
+ krb5_kdc_configuration *config,
+ int flags,
+ krb5_principal cp,
+ const char *cpn,
+ const char *krbtgt_realm,
+ HDB **clientdb,
+ hdb_entry_ex **client_out)
+{
+ krb5_error_code ret;
+ hdb_entry_ex *client = NULL;
+
+ *client_out = NULL;
+
+ ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
+ NULL, clientdb, &client);
+ if (ret == HDB_ERR_NOT_FOUND_HERE) {
+ /*
+ * This is OK, we are just trying to find out if they have
+ * been disabled or deleted in the meantime; missing secrets
+ * are OK.
+ */
+ } else if (ret) {
+ /*
+ * If the client belongs to the same realm as our TGS, it
+ * should exist in the local database.
+ */
+ const char *msg;
+
+ if (strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
+ if (ret == HDB_ERR_NOENTRY)
+ ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ kdc_log(context, config, 4, "Client no longer in database: %s", cpn);
+ return ret;
+ }
+
+ msg = krb5_get_error_message(context, ret);
+ kdc_log(context, config, 4, "Client not found in database: %s", msg);
+ krb5_free_error_message(context, msg);
+ } else if (client->entry.flags.invalid || !client->entry.flags.client) {
+ kdc_log(context, config, 4, "Client has invalid bit set");
+ _kdc_free_ent(context, client);
+ return KRB5KDC_ERR_POLICY;
+ }
+
+ *client_out = client;
+
+ return 0;
+}
+
static krb5_error_code
tgs_build_reply(krb5_context context,
krb5_kdc_configuration *config,
KDC_REQ_BODY *b,
hdb_entry_ex *krbtgt,
krb5_enctype krbtgt_etype,
+ Key *tkey_check,
const krb5_keyblock *replykey,
int rk_is_subkey,
krb5_ticket *ticket,
const EncryptionKey *ekey;
krb5_keyblock sessionkey;
krb5_kvno kvno;
- krb5_data rspac;
+ krb5_pac mspac = NULL;
+ uint16_t rodc_id;
+ krb5_boolean add_ticket_sig = FALSE;
hdb_entry_ex *krbtgt_out = NULL;
int nloop = 0;
EncTicketPart adtkt;
char opt_str[128];
- int signedpath = 0;
+ krb5_boolean kdc_issued = FALSE;
- Key *tkey_check;
Key *tkey_sign;
int flags = HDB_F_FOR_TGS_REQ;
memset(&sessionkey, 0, sizeof(sessionkey));
memset(&adtkt, 0, sizeof(adtkt));
- krb5_data_zero(&rspac);
memset(&enc_pa_data, 0, sizeof(enc_pa_data));
s = b->sname;
* backward.
*/
- /*
- * Validate authoriation data
- */
-
- ret = hdb_enctype2key(context, &krbtgt->entry,
- krbtgt_etype, &tkey_check);
- if(ret) {
- kdc_log(context, config, 0,
- "Failed to find key for krbtgt PAC check");
- goto out;
- }
-
/* Now refetch the primary krbtgt, and get the current kvno (the
* sign check may have been on an old kvno, and the server may
* have been an incoming trust) */
goto out;
}
- ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
- NULL, &clientdb, &client);
- if(ret == HDB_ERR_NOT_FOUND_HERE) {
- /* This is OK, we are just trying to find out if they have
- * been disabled or deleted in the meantime, missing secrets
- * is OK */
- } else if(ret){
- const char *krbtgt_realm, *msg;
-
- /*
- * If the client belongs to the same realm as our krbtgt, it
- * should exist in the local database.
- *
- */
-
- krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
-
- if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
- if (ret == HDB_ERR_NOENTRY)
- ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
- kdc_log(context, config, 1, "Client no longer in database: %s",
- cpn);
- goto out;
- }
-
- msg = krb5_get_error_message(context, ret);
- kdc_log(context, config, 1, "Client not found in database: %s", msg);
- krb5_free_error_message(context, msg);
- }
+ ret = db_fetch_client(context, config, flags, cp, cpn,
+ krb5_principal_get_realm(context, krbtgt_out->entry.principal),
+ &clientdb, &client);
+ if (ret)
+ goto out;
- ret = check_PAC(context, config, cp, NULL,
- client, server, krbtgt,
- &tkey_check->key,
- ekey, &tkey_sign->key,
- tgt, &rspac, &signedpath);
+ ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt,
+ &tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac);
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
kdc_log(context, config, 0,
goto out;
/* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
- if(rspac.data) {
- krb5_pac p = NULL;
- krb5_data_free(&rspac);
- ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &p);
+ if (mspac) {
+ krb5_pac_free(context, mspac);
+ mspac = NULL;
+ ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &mspac);
if (ret) {
kdc_log(context, config, 0, "PAC generation failed for -- %s",
tpn);
goto out;
}
- if (p != NULL) {
- ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
- s4u2self_impersonated_client->entry.principal,
- ekey, &tkey_sign->key,
- &rspac);
- krb5_pac_free(context, p);
- if (ret) {
- kdc_log(context, config, 0, "PAC signing failed for -- %s",
- tpn);
- goto out;
- }
- }
}
/*
&& b->additional_tickets->len != 0
&& b->kdc_options.enc_tkt_in_skey == 0)
{
- int ad_signedpath = 0;
+ hdb_entry_ex *adclient = NULL;
+ krb5_boolean ad_kdc_issued = FALSE;
Key *clientkey;
Ticket *t;
/*
- * Require that the KDC have issued the service's krbtgt (not
- * self-issued ticket with kimpersonate(1).
+ * We require that the service's krbtgt has a PAC.
*/
- if (!signedpath) {
+ if (mspac == NULL) {
ret = KRB5KDC_ERR_BADOPTION;
kdc_log(context, config, 0,
- "Constrained delegation done on service ticket %s/%s",
+ "Constrained delegation without PAC %s/%s",
cpn, spn);
goto out;
}
+ krb5_pac_free(context, mspac);
+ mspac = NULL;
+
t = &b->additional_tickets->val[0];
ret = hdb_enctype2key(context, &client->entry,
goto out;
}
- krb5_data_free(&rspac);
+ /* Try lookup the delegated client in DB */
+ ret = db_fetch_client(context, config, flags, tp, tpn,
+ krb5_principal_get_realm(context, krbtgt_out->entry.principal),
+ NULL, &adclient);
+ if (ret)
+ goto out;
+
+ if (adclient != NULL) {
+ ret = kdc_check_flags(context, config,
+ adclient, tpn,
+ server, spn,
+ FALSE);
+ if (ret) {
+ _kdc_free_ent(context, adclient);
+ goto out;
+ }
+ }
/*
- * generate the PAC for the user.
- *
* TODO: pass in t->sname and t->realm and build
* a S4U_DELEGATION_INFO blob to the PAC.
*/
- ret = check_PAC(context, config, tp, dp,
- client, server, krbtgt,
- &clientkey->key,
- ekey, &tkey_sign->key,
- &adtkt, &rspac, &ad_signedpath);
+ ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client,
+ &clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac);
+ if (adclient)
+ _kdc_free_ent(context, adclient);
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
kdc_log(context, config, 0,
goto out;
}
- if (!ad_signedpath) {
+ if (mspac == NULL || !ad_kdc_issued) {
ret = KRB5KDC_ERR_BADOPTION;
kdc_log(context, config, 0,
- "Ticket not signed with PAC nor SignedPath service %s failed "
- "for delegation to %s for client %s (%s)"
- "from %s",
- spn, tpn, dpn, cpn, from);
+ "Ticket not signed with PAC; service %s failed for "
+ "for delegation to %s for client %s (%s) from %s; (%s).",
+ spn, tpn, dpn, cpn, from, mspac ? "Ticket unsigned" : "No PAC");
goto out;
}
}
}
+ /*
+ * Only add ticket signature if the requested server is not krbtgt, and
+ * either the header server is krbtgt or, in the case of renewal/validation
+ * if it was signed with PAC ticket signature and we verified it.
+ * Currently Heimdal only allows renewal of krbtgt anyway but that might
+ * change one day (see issue #763) so make sure to check for it.
+ */
+
+ if (kdc_issued &&
+ !krb5_principal_is_krbtgt(context, server->entry.principal))
+ add_ticket_sig = TRUE;
+
+ /*
+ * Active-Directory implementations use the high part of the kvno as the
+ * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
+ */
+
+ rodc_id = krbtgt_out->entry.kvno >> 16;
+
/*
*
*/
replykey,
rk_is_subkey,
ekey,
+ &tkey_sign->key,
&sessionkey,
kvno,
*auth_data,
client,
cp,
krbtgt_out,
- krbtgt_etype,
- &rspac,
+ mspac,
+ rodc_id,
+ add_ticket_sig,
&enc_pa_data,
e_text,
reply);
if (dpn)
free(dpn);
- krb5_data_free(&rspac);
krb5_free_keyblock_contents(context, &sessionkey);
if(krbtgt_out)
_kdc_free_ent(context, krbtgt_out);
free_EncTicketPart(&adtkt);
+ if (mspac)
+ krb5_pac_free(context, mspac);
+
return ret;
}
krb5_error_code ret;
int i = 0;
const PA_DATA *tgs_req;
+ Key *header_key = NULL;
hdb_entry_ex *krbtgt = NULL;
krb5_ticket *ticket = NULL;
&csec, &cusec,
&auth_data,
&replykey,
+ &header_key,
&rk_is_subkey);
if (ret == HDB_ERR_NOT_FOUND_HERE) {
/* kdc_log() is called in tgs_parse_request() */
&req->req_body,
krbtgt,
krbtgt_etype,
+ header_key,
replykey,
rk_is_subkey,
ticket,
krb5_pac *pac)
{
*pac = NULL;
- if (windcft == NULL)
+ if (krb5_config_get_bool_default(context, NULL, FALSE, "realms",
+ client->entry.principal->realm,
+ "disable_pac", NULL))
return 0;
+ if (windcft == NULL) {
+ return krb5_pac_init(context, pac);
+ }
+
if (windcft->pac_pk_generate != NULL && pk_reply_key != NULL)
return (windcft->pac_pk_generate)(windcctx, context,
client, pk_reply_key, pac);
hdb_entry_ex *client,
hdb_entry_ex *server,
hdb_entry_ex *krbtgt,
- krb5_pac *pac,
- int *verified)
+ krb5_pac *pac)
{
krb5_error_code ret;
if (windcft == NULL)
- return 0;
+ return KRB5_PLUGIN_NO_HANDLE;
ret = windcft->pac_verify(windcctx, context,
client_principal,
delegated_proxy_principal,
client, server, krbtgt, pac);
- if (ret == 0)
- *verified = 1;
return ret;
}
* krb5_pac_init and fill in the PAC structure for the principal using
* krb5_pac_add_buffer.
*
- * The PAC verify function should verify all components in the PAC
- * using krb5_pac_get_types and krb5_pac_get_buffer for all types.
+ * The PAC verify function should verify the PAC KDC signatures by fetching
+ * the right KDC key and calling krb5_pac_verify() with that KDC key.
+ * Optionally, update the PAC buffers upon success.
*
* Check client access function check if the client is authorized.
*/
--- /dev/null
+/*
+ * Copyright (c) 1997-2021 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (c) 2021 Isaac Boukris
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "krb5_locl.h"
+
+/*
+ * Add the AuthorizationData `data´ of `type´ to the last element in
+ * the sequence of authorization_data in `tkt´ wrapped in an IF_RELEVANT
+ */
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+_kdc_tkt_add_if_relevant_ad(krb5_context context,
+ EncTicketPart *tkt,
+ int type,
+ const krb5_data *data)
+{
+ krb5_error_code ret;
+ size_t size = 0;
+
+ if (tkt->authorization_data == NULL) {
+ tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
+ if (tkt->authorization_data == NULL) {
+ return krb5_enomem(context);
+ }
+ }
+
+ /* add the entry to the last element */
+ {
+ AuthorizationData ad = { 0, NULL };
+ AuthorizationDataElement ade;
+
+ ade.ad_type = type;
+ ade.ad_data = *data;
+
+ ret = add_AuthorizationData(&ad, &ade);
+ if (ret) {
+ krb5_set_error_message(context, ret, "add AuthorizationData failed");
+ return ret;
+ }
+
+ ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
+
+ ASN1_MALLOC_ENCODE(AuthorizationData,
+ ade.ad_data.data, ade.ad_data.length,
+ &ad, &size, ret);
+ free_AuthorizationData(&ad);
+ if (ret) {
+ krb5_set_error_message(context, ret, "ASN.1 encode of "
+ "AuthorizationData failed");
+ return ret;
+ }
+ if (ade.ad_data.length != size)
+ krb5_abortx(context, "internal asn.1 encoder error");
+
+ ret = add_AuthorizationData(tkt->authorization_data, &ade);
+ der_free_octet_string(&ade.ad_data);
+ if (ret) {
+ krb5_set_error_message(context, ret, "add AuthorizationData failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Insert a PAC wrapped in AD-IF-RELEVANT container as the first AD element,
+ * as some clients such as Windows may fail to parse it otherwise.
+ */
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+_kdc_tkt_insert_pac(krb5_context context,
+ EncTicketPart *tkt,
+ const krb5_data *data)
+{
+ AuthorizationDataElement ade;
+ unsigned int i;
+ krb5_error_code ret;
+
+ ret = _kdc_tkt_add_if_relevant_ad(context, tkt, KRB5_AUTHDATA_WIN2K_PAC,
+ data);
+ if (ret)
+ return ret;
+
+ heim_assert(tkt->authorization_data->len != 0, "No authorization_data!");
+ ade = tkt->authorization_data->val[tkt->authorization_data->len - 1];
+ for (i = 0; i < tkt->authorization_data->len - 1; i++) {
+ tkt->authorization_data->val[i + 1] = tkt->authorization_data->val[i];
+ }
+ tkt->authorization_data->val[0] = ade;
+
+ return 0;
+}
struct PAC_INFO_BUFFER *server_checksum;
struct PAC_INFO_BUFFER *privsvr_checksum;
struct PAC_INFO_BUFFER *logon_name;
+ struct PAC_INFO_BUFFER *ticket_checksum;
+ krb5_data ticket_sign_data;
};
#define PAC_ALIGNMENT 8
#define PAC_PRIVSVR_CHECKSUM 7
#define PAC_LOGON_NAME 10
#define PAC_CONSTRAINED_DELEGATION 11
+#define PAC_TICKET_CHECKSUM 16
#define CHECK(r,f,l) \
do { \
CHECK(ret, krb5_ret_uint32(sp, &tmp2), out);
if (tmp < 1) {
ret = EINVAL; /* Too few buffers */
- krb5_set_error_message(context, ret, N_("PAC have too few buffer", ""));
+ krb5_set_error_message(context, ret, N_("PAC has too few buffers", ""));
goto out;
}
if (tmp2 != 0) {
ret = EINVAL; /* Wrong version */
krb5_set_error_message(context, ret,
- N_("PAC have wrong version %d", ""),
+ N_("PAC has wrong version %d", ""),
(int)tmp2);
goto out;
}
if (p->pac->buffers[i].offset_lo > len) {
ret = EINVAL;
krb5_set_error_message(context, ret,
- N_("PAC offset off end", ""));
+ N_("PAC offset overflow", ""));
goto out;
}
if (p->pac->buffers[i].offset_lo < header_end) {
}
if (p->pac->buffers[i].buffersize > len - p->pac->buffers[i].offset_lo){
ret = EINVAL;
- krb5_set_error_message(context, ret, N_("PAC length off end", ""));
+ krb5_set_error_message(context, ret, N_("PAC length overflow", ""));
goto out;
}
if (p->server_checksum) {
ret = EINVAL;
krb5_set_error_message(context, ret,
- N_("PAC have two server checksums", ""));
+ N_("PAC has multiple server checksums", ""));
goto out;
}
p->server_checksum = &p->pac->buffers[i];
if (p->privsvr_checksum) {
ret = EINVAL;
krb5_set_error_message(context, ret,
- N_("PAC have two KDC checksums", ""));
+ N_("PAC has multiple KDC checksums", ""));
goto out;
}
p->privsvr_checksum = &p->pac->buffers[i];
if (p->logon_name) {
ret = EINVAL;
krb5_set_error_message(context, ret,
- N_("PAC have two logon names", ""));
+ N_("PAC has multiple logon names", ""));
goto out;
}
p->logon_name = &p->pac->buffers[i];
+ } else if (p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
+ if (p->ticket_checksum) {
+ ret = EINVAL;
+ krb5_set_error_message(context, ret,
+ N_("PAC has multiple ticket checksums", ""));
+ goto out;
+ }
+ p->ticket_checksum = &p->pac->buffers[i];
}
}
krb5_pac_free(krb5_context context, krb5_pac pac)
{
krb5_data_free(&pac->data);
+ krb5_data_free(&pac->ticket_sign_data);
free(pac->pac);
free(pac);
}
uint32_t type;
krb5_error_code ret;
Checksum cksum;
+ size_t cksumsize;
memset(&cksum, 0, sizeof(cksum));
CHECK(ret, krb5_ret_uint32(sp, &type), out);
cksum.cksumtype = type;
- cksum.checksum.length =
- sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR);
+
+ ret = krb5_checksumsize(context, type, &cksumsize);
+ if (ret)
+ goto out;
+
+ /* Allow for RODCIdentifier trailer, see MS-PAC 2.8 */
+ if (cksumsize > (sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR))) {
+ ret = EINVAL;
+ goto out;
+ }
+ cksum.checksum.length = cksumsize;
cksum.checksum.data = malloc(cksum.checksum.length);
if (cksum.checksum.data == NULL) {
ret = krb5_enomem(context);
return ret;
}
-
/**
* Verify the PAC.
*
return EINVAL;
}
- ret = verify_logonname(context,
- pac->logon_name,
- &pac->data,
- authtime,
- principal);
- if (ret)
- return ret;
+ if (principal != NULL) {
+ ret = verify_logonname(context, pac->logon_name, &pac->data, authtime,
+ principal);
+ if (ret)
+ return ret;
+ }
+
+ if (pac->server_checksum->buffersize < 4 ||
+ pac->privsvr_checksum->buffersize < 4)
+ return EINVAL;
/*
* in the service case, clean out data option of the privsvr and
* server checksum before checking the checksum.
*/
+ if (server != NULL)
{
krb5_data *copy;
privsvr);
if (ret)
return ret;
+
+ if (pac->ticket_sign_data.length != 0) {
+ if (pac->ticket_checksum == NULL) {
+ krb5_set_error_message(context, EINVAL,
+ "PAC missing ticket checksum");
+ return EINVAL;
+ }
+
+ ret = verify_checksum(context, pac->ticket_checksum, &pac->data,
+ pac->ticket_sign_data.data,
+ pac->ticket_sign_data.length, privsvr);
+ if (ret)
+ return ret;
+ }
}
return 0;
krb5_principal principal,
const krb5_keyblock *server_key,
const krb5_keyblock *priv_key,
+ uint16_t rodc_id,
krb5_data *data)
{
krb5_error_code ret;
krb5_storage *sp = NULL, *spdata = NULL;
uint32_t end;
size_t server_size, priv_size;
- uint32_t server_offset = 0, priv_offset = 0;
+ uint32_t server_offset = 0, priv_offset = 0, ticket_offset = 0;
uint32_t server_cksumtype = 0, priv_cksumtype = 0;
int num = 0;
size_t i;
p->server_checksum = &p->pac->buffers[i];
}
if (p->server_checksum != &p->pac->buffers[i]) {
- ret = EINVAL;
+ ret = KRB5KDC_ERR_BADOPTION;
krb5_set_error_message(context, ret,
- N_("PAC have two server checksums", ""));
+ N_("PAC has multiple server checksums", ""));
goto out;
}
} else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) {
p->privsvr_checksum = &p->pac->buffers[i];
}
if (p->privsvr_checksum != &p->pac->buffers[i]) {
- ret = EINVAL;
+ ret = KRB5KDC_ERR_BADOPTION;
krb5_set_error_message(context, ret,
- N_("PAC have two KDC checksums", ""));
+ N_("PAC has multiple KDC checksums", ""));
goto out;
}
} else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
p->logon_name = &p->pac->buffers[i];
}
if (p->logon_name != &p->pac->buffers[i]) {
- ret = EINVAL;
+ ret = KRB5KDC_ERR_BADOPTION;
+ krb5_set_error_message(context, ret,
+ N_("PAC has multiple logon names", ""));
+ goto out;
+ }
+ } else if (p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
+ if (p->ticket_checksum == NULL) {
+ p->ticket_checksum = &p->pac->buffers[i];
+ }
+ if (p->ticket_checksum != &p->pac->buffers[i]) {
+ ret = KRB5KDC_ERR_BADOPTION;
krb5_set_error_message(context, ret,
- N_("PAC have two logon names", ""));
+ N_("PAC has multiple ticket checksums", ""));
goto out;
}
}
num++;
if (p->privsvr_checksum == NULL)
num++;
+ if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL)
+ num++;
if (num) {
void *ptr;
memset(p->privsvr_checksum, 0, sizeof(*p->privsvr_checksum));
p->privsvr_checksum->type = PAC_PRIVSVR_CHECKSUM;
}
+ if (p->ticket_sign_data.length != 0 && p->ticket_checksum == NULL) {
+ p->ticket_checksum = &p->pac->buffers[p->pac->numbuffers++];
+ memset(p->ticket_checksum, 0, sizeof(*p->privsvr_checksum));
+ p->ticket_checksum->type = PAC_TICKET_CHECKSUM;
+ }
}
/* Calculate LOGON NAME */
ret = pac_checksum(context, server_key, &server_cksumtype, &server_size);
if (ret)
goto out;
+
ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size);
if (ret)
goto out;
priv_offset = end + 4;
CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
CHECK(ret, fill_zeros(context, spdata, priv_size), out);
+ if (rodc_id != 0) {
+ len += sizeof(rodc_id);
+ CHECK(ret, fill_zeros(context, spdata, sizeof(rodc_id)), out);
+ }
+ } else if (p->ticket_sign_data.length != 0 &&
+ p->pac->buffers[i].type == PAC_TICKET_CHECKSUM) {
+ len = priv_size + 4;
+ ticket_offset = end + 4;
+ CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out);
+ CHECK(ret, fill_zeros(context, spdata, priv_size), out);
+ if (rodc_id != 0) {
+ len += sizeof(rodc_id);
+ CHECK(ret, krb5_store_uint16(spdata, rodc_id), out);
+ }
} else if (p->pac->buffers[i].type == PAC_LOGON_NAME) {
len = krb5_storage_write(spdata, logon.data, logon.length);
if (logon.length != len) {
- ret = EINVAL;
+ ret = KRB5KDC_ERR_BADOPTION;
goto out;
}
} else {
}
/* sign */
+ if (p->ticket_sign_data.length) {
+ ret = create_checksum(context, priv_key, priv_cksumtype,
+ p->ticket_sign_data.data,
+ p->ticket_sign_data.length,
+ (char *)d.data + ticket_offset, priv_size);
+ if (ret) {
+ krb5_data_free(&d);
+ goto out;
+ }
+ }
ret = create_checksum(context, server_key, server_cksumtype,
d.data, d.length,
(char *)d.data + server_offset, server_size);
goto out;
}
+ if (rodc_id != 0) {
+ krb5_data rd;
+ krb5_storage *rs = krb5_storage_emem();
+ if (rs == NULL) {
+ krb5_data_free(&d);
+ ret = krb5_enomem(context);
+ goto out;
+ }
+ krb5_storage_set_flags(rs, KRB5_STORAGE_BYTEORDER_LE);
+ ret = krb5_store_uint16(rs, rodc_id);
+ if (ret) {
+ krb5_storage_free(rs);
+ krb5_data_free(&d);
+ goto out;
+ }
+ ret = krb5_storage_to_data(rs, &rd);
+ krb5_storage_free(rs);
+ if (ret) {
+ krb5_data_free(&d);
+ goto out;
+ }
+ heim_assert(rd.length == sizeof(rodc_id), "invalid length");
+ memcpy((char *)d.data + priv_offset + priv_size, rd.data, rd.length);
+ krb5_data_free(&rd);
+ }
+
/* done */
*data = d;
krb5_storage_free(spdata);
return ret;
}
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+_krb5_pac_get_kdc_checksum_info(krb5_context context,
+ krb5_pac pac,
+ krb5_cksumtype *cstype,
+ uint16_t *rodc_id)
+{
+ krb5_error_code ret;
+ krb5_storage *sp = NULL;
+ const struct PAC_INFO_BUFFER *sig;
+ size_t cksumsize, prefix;
+ uint32_t type = 0;
+
+ *cstype = 0;
+ *rodc_id = 0;
+
+ sig = pac->privsvr_checksum;
+ if (sig == NULL) {
+ krb5_set_error_message(context, KRB5KDC_ERR_BADOPTION,
+ "PAC missing kdc checksum");
+ return KRB5KDC_ERR_BADOPTION;
+ }
+
+ sp = krb5_storage_from_mem((char *)pac->data.data + sig->offset_lo,
+ sig->buffersize);
+ if (sp == NULL)
+ return krb5_enomem(context);
+
+ krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
+
+ ret = krb5_ret_uint32(sp, &type);
+ if (ret)
+ goto out;
+
+ ret = krb5_checksumsize(context, type, &cksumsize);
+ if (ret)
+ goto out;
+
+ prefix = krb5_storage_seek(sp, 0, SEEK_CUR);
+
+ if ((sig->buffersize - prefix) >= cksumsize + 2) {
+ krb5_storage_seek(sp, cksumsize, SEEK_CUR);
+ ret = krb5_ret_uint16(sp, rodc_id);
+ if (ret)
+ goto out;
+ }
+
+ *cstype = type;
+
+out:
+ krb5_storage_free(sp);
+
+ return ret;
+}
+
+static unsigned char single_zero = '\0';
+static krb5_data single_zero_pac = { 1, &single_zero };
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+_krb5_kdc_pac_ticket_parse(krb5_context context,
+ EncTicketPart *tkt,
+ krb5_boolean *signedticket,
+ krb5_pac *ppac)
+{
+ AuthorizationData *ad = tkt->authorization_data;
+ krb5_boolean pac_found = FALSE;
+ krb5_pac pac = NULL;
+ unsigned i, j;
+ size_t len = 0;
+ krb5_error_code ret;
+
+ *signedticket = FALSE;
+ *ppac = NULL;
+
+ if (ad == NULL || ad->len == 0)
+ return 0;
+
+ for (i = 0; i < ad->len; i++) {
+ AuthorizationData child;
+
+ if (ad->val[i].ad_type == KRB5_AUTHDATA_WIN2K_PAC)
+ return KRB5KDC_ERR_BADOPTION;
+
+ if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
+ continue;
+
+ ret = decode_AuthorizationData(ad->val[i].ad_data.data,
+ ad->val[i].ad_data.length,
+ &child,
+ NULL);
+ if (ret) {
+ krb5_set_error_message(context, ret, "Failed to decode "
+ "AD-IF-RELEVANT with %d", ret);
+ return ret;
+ }
+
+ for (j = 0; j < child.len; j++) {
+ if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
+ krb5_data adifr_data = ad->val[i].ad_data;
+ krb5_data pac_data = child.val[j].ad_data;
+ krb5_data recoded_adifr;
+
+ if (pac_found) {
+ free_AuthorizationData(&child);
+ return KRB5KDC_ERR_BADOPTION;
+ }
+ pac_found = TRUE;
+
+ ret = krb5_pac_parse(context,
+ pac_data.data,
+ pac_data.length,
+ &pac);
+ if (ret) {
+ free_AuthorizationData(&child);
+ return ret;
+ }
+
+ if (pac->ticket_checksum == NULL) {
+ free_AuthorizationData(&child);
+ *ppac = pac;
+ continue;
+ }
+
+ /*
+ * Encode the ticket with the PAC replaced with a single zero
+ * byte, to be used as input data to the ticket signature.
+ */
+
+ child.val[j].ad_data = single_zero_pac;
+
+ ASN1_MALLOC_ENCODE(AuthorizationData, recoded_adifr.data,
+ recoded_adifr.length, &child, &len, ret);
+ if (recoded_adifr.length != len)
+ krb5_abortx(context, "Internal error in ASN.1 encoder");
+
+ child.val[j].ad_data = pac_data;
+ free_AuthorizationData(&child);
+
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
+
+ ad->val[i].ad_data = recoded_adifr;
+
+ ASN1_MALLOC_ENCODE(EncTicketPart,
+ pac->ticket_sign_data.data,
+ pac->ticket_sign_data.length, tkt, &len,
+ ret);
+ if(pac->ticket_sign_data.length != len)
+ krb5_abortx(context, "Internal error in ASN.1 encoder");
+
+ ad->val[i].ad_data = adifr_data;
+ krb5_data_free(&recoded_adifr);
+
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
+
+ *signedticket = TRUE;
+ *ppac = pac;
+ }
+ }
+ free_AuthorizationData(&child);
+ }
+ return 0;
+}
+
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
+_krb5_kdc_pac_sign_ticket(krb5_context context,
+ const krb5_pac pac,
+ krb5_principal client,
+ const krb5_keyblock *server_key,
+ const krb5_keyblock *kdc_key,
+ uint16_t rodc_id,
+ krb5_boolean add_ticket_sig,
+ EncTicketPart *tkt)
+{
+ krb5_error_code ret;
+ krb5_data tkt_data;
+ krb5_data rspac;
+
+ krb5_data_zero(&rspac);
+ krb5_data_zero(&tkt_data);
+
+ krb5_data_free(&pac->ticket_sign_data);
+
+ if (add_ticket_sig) {
+ size_t len = 0;
+
+ ret = _kdc_tkt_insert_pac(context, tkt, &single_zero_pac);
+ if (ret)
+ return ret;
+
+ ASN1_MALLOC_ENCODE(EncTicketPart, tkt_data.data, tkt_data.length,
+ tkt, &len, ret);
+ if(tkt_data.length != len)
+ krb5_abortx(context, "Internal error in ASN.1 encoder");
+ if (ret)
+ return ret;
+
+ ret = remove_AuthorizationData(tkt->authorization_data, 0);
+ if (ret) {
+ krb5_data_free(&tkt_data);
+ return ret;
+ }
+
+ pac->ticket_sign_data = tkt_data;
+ }
+
+ ret = _krb5_pac_sign(context, pac, tkt->authtime, client, server_key,
+ kdc_key, rodc_id, &rspac);
+ if (ret)
+ return ret;
+
+ return _kdc_tkt_insert_pac(context, tkt, &rspac);
+}
_krb5_get_host_realm_int;
_krb5_get_int;
_krb5_pac_sign;
+ _krb5_kdc_pac_sign_ticket;
+ _krb5_kdc_pac_ticket_parse;
+ _krb5_pac_get_kdc_checksum_info;
+ _kdc_tkt_insert_pac;
+ _kdc_tkt_add_if_relevant_ad;
_krb5_parse_moduli;
_krb5_pk_kdf;
_krb5_pk_load_id;
KRB5_SOURCE = [os.path.join('lib/krb5/', x) for x in to_list(
'''acache.c add_et_list.c
addr_families.c appdefault.c
- asn1_glue.c auth_context.c
+ asn1_glue.c auth_context.c authdata.c
build_ap_req.c build_auth.c cache.c
changepw.c codec.c config_file.c
constants.c convert_creds.c
planoldpythontestsuite("ad_dc:local", "samba.tests.dckeytab", extra_args=['-U"$USERNAME%$PASSWORD"'])
have_fast_support = int('SAMBA_USES_MITKDC' in config_hash)
-tkt_sig_support = 0
+tkt_sig_support = int('SAMBA4_USES_HEIMDAL' in config_hash)
planoldpythontestsuite("none", "samba.tests.krb5.kcrypto")
planoldpythontestsuite("ad_dc_default", "samba.tests.krb5.simple_tests",
environ={'SERVICE_USERNAME':'$SERVER',