mirror of
https://github.com/samba-team/samba.git
synced 2025-01-10 01:18:15 +03:00
s4:kdc: Check ticket signature
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14642 Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
parent
3bdce12789
commit
02fa69c6c7
@ -70,13 +70,8 @@
|
||||
#
|
||||
# S4U tests
|
||||
#
|
||||
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_bronze_bit_constrained_delegation_old_checksum
|
||||
^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_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_constrained_delegation_zeroed_client_checksum
|
||||
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_constrained_delegation_zeroed_service_checksum
|
||||
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_existing_delegation_info
|
||||
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_missing_client_checksum
|
||||
^samba.tests.krb5.s4u_tests.samba.tests.krb5.s4u_tests.S4UKerberosTests.test_rbcd_no_client_pac_a
|
||||
@ -88,10 +83,6 @@
|
||||
^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_trusted_empty_allowed
|
||||
#
|
||||
# RODC tests
|
||||
#
|
||||
^samba.tests.krb5.rodc_tests.samba.tests.krb5.rodc_tests.RodcKerberosTests.test_rodc_ticket_signature
|
||||
#
|
||||
# The lack of KRB5SignedPath means we no longer return
|
||||
# KRB5KRB_ERR_RESPONSE_TOO_BIG in this specific case
|
||||
#
|
||||
|
@ -23,7 +23,10 @@
|
||||
|
||||
#include "includes.h"
|
||||
#include "kdc/kdc-glue.h"
|
||||
#include "kdc/db-glue.h"
|
||||
#include "kdc/pac-glue.h"
|
||||
#include "sdb.h"
|
||||
#include "sdb_hdb.h"
|
||||
|
||||
/*
|
||||
* Given the right private pointer from hdb_samba4,
|
||||
@ -94,15 +97,13 @@ static krb5_error_code samba_wdc_get_pac_compat(void *priv, krb5_context context
|
||||
return samba_wdc_get_pac(priv, context, client, NULL, pac);
|
||||
}
|
||||
|
||||
/* Resign (and reform, including possibly new groups) a PAC */
|
||||
|
||||
static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
|
||||
const krb5_principal client_principal,
|
||||
const krb5_principal delegated_proxy_principal,
|
||||
struct hdb_entry_ex *client,
|
||||
struct hdb_entry_ex *server,
|
||||
struct hdb_entry_ex *krbtgt,
|
||||
krb5_pac *pac)
|
||||
static krb5_error_code samba_wdc_reget_pac2(krb5_context context,
|
||||
const krb5_principal delegated_proxy_principal,
|
||||
struct hdb_entry_ex *client,
|
||||
struct hdb_entry_ex *server,
|
||||
struct hdb_entry_ex *krbtgt,
|
||||
krb5_pac *pac,
|
||||
krb5_cksumtype ctype)
|
||||
{
|
||||
struct samba_kdc_entry *p =
|
||||
talloc_get_type_abort(server->ctx,
|
||||
@ -110,15 +111,13 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
|
||||
struct samba_kdc_entry *krbtgt_skdc_entry =
|
||||
talloc_get_type_abort(krbtgt->ctx,
|
||||
struct samba_kdc_entry);
|
||||
TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac context");
|
||||
TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac2 context");
|
||||
krb5_pac new_pac = NULL;
|
||||
DATA_BLOB *pac_blob = NULL;
|
||||
DATA_BLOB *upn_blob = NULL;
|
||||
DATA_BLOB *deleg_blob = NULL;
|
||||
krb5_error_code ret;
|
||||
NTSTATUS nt_status;
|
||||
struct PAC_SIGNATURE_DATA *pac_srv_sig;
|
||||
struct PAC_SIGNATURE_DATA *pac_kdc_sig;
|
||||
bool is_in_db, is_untrusted;
|
||||
size_t num_types = 0;
|
||||
uint32_t *types = NULL;
|
||||
@ -130,6 +129,7 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
|
||||
ssize_t upn_dns_info_idx = -1;
|
||||
ssize_t srv_checksum_idx = -1;
|
||||
ssize_t kdc_checksum_idx = -1;
|
||||
ssize_t tkt_checksum_idx = -1;
|
||||
|
||||
if (!mem_ctx) {
|
||||
return ENOMEM;
|
||||
@ -150,6 +150,71 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (delegated_proxy_principal != NULL) {
|
||||
krb5_enctype etype;
|
||||
Key *key = NULL;
|
||||
|
||||
if (!is_in_db) {
|
||||
/*
|
||||
* The RODC-issued PAC was signed by a KDC entry that we
|
||||
* don't have a key for. The server signature is not
|
||||
* trustworthy, since it could have been created by the
|
||||
* server we got the ticket from. We must not proceed as
|
||||
* otherwise the ticket signature is unchecked.
|
||||
*/
|
||||
talloc_free(mem_ctx);
|
||||
return HDB_ERR_NOT_FOUND_HERE;
|
||||
}
|
||||
|
||||
/* Fetch the correct key depending on the checksum type. */
|
||||
if (ctype == CKSUMTYPE_HMAC_MD5) {
|
||||
etype = ENCTYPE_ARCFOUR_HMAC;
|
||||
} else {
|
||||
ret = krb5_cksumtype_to_enctype(context,
|
||||
ctype,
|
||||
&etype);
|
||||
if (ret != 0) {
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = hdb_enctype2key(context, &krbtgt->entry, etype, &key);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check the KDC and ticket signatures. */
|
||||
ret = krb5_pac_verify(context,
|
||||
*pac,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&key->key);
|
||||
if (ret != 0) {
|
||||
DEBUG(1, ("PAC KDC signature failed to verify\n"));
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
|
||||
if (!deleg_blob) {
|
||||
talloc_free(mem_ctx);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
nt_status = samba_kdc_update_delegation_info_blob(mem_ctx,
|
||||
context, *pac,
|
||||
server->entry.principal,
|
||||
delegated_proxy_principal,
|
||||
deleg_blob);
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
DEBUG(0, ("Building PAC failed: %s\n",
|
||||
nt_errstr(nt_status)));
|
||||
talloc_free(mem_ctx);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_untrusted) {
|
||||
struct samba_kdc_entry *client_skdc_entry = NULL;
|
||||
|
||||
@ -173,52 +238,10 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
pac_srv_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA);
|
||||
if (!pac_srv_sig) {
|
||||
talloc_free(mem_ctx);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
pac_kdc_sig = talloc_zero(mem_ctx, struct PAC_SIGNATURE_DATA);
|
||||
if (!pac_kdc_sig) {
|
||||
talloc_free(mem_ctx);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
|
||||
krbtgt_skdc_entry->kdc_db_ctx->samdb,
|
||||
*pac, pac_blob,
|
||||
pac_srv_sig, pac_kdc_sig);
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
DEBUG(0, ("Building PAC failed: %s\n",
|
||||
nt_errstr(nt_status)));
|
||||
talloc_free(mem_ctx);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (is_in_db) {
|
||||
/* Now check the KDC signature, fetching the correct key based on the enc type */
|
||||
ret = kdc_check_pac(context, pac_srv_sig->signature, pac_kdc_sig, krbtgt);
|
||||
if (ret != 0) {
|
||||
DEBUG(1, ("PAC KDC signature failed to verify\n"));
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delegated_proxy_principal) {
|
||||
deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
|
||||
if (!deleg_blob) {
|
||||
talloc_free(mem_ctx);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
nt_status = samba_kdc_update_delegation_info_blob(mem_ctx,
|
||||
context, *pac,
|
||||
server->entry.principal,
|
||||
delegated_proxy_principal,
|
||||
deleg_blob);
|
||||
NULL, NULL);
|
||||
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
DEBUG(0, ("Building PAC failed: %s\n",
|
||||
nt_errstr(nt_status)));
|
||||
@ -308,6 +331,18 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
|
||||
}
|
||||
kdc_checksum_idx = i;
|
||||
break;
|
||||
case PAC_TYPE_TICKET_CHECKSUM:
|
||||
if (tkt_checksum_idx != -1) {
|
||||
DEBUG(1, ("ticket checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
|
||||
types[i],
|
||||
tkt_checksum_idx,
|
||||
i));
|
||||
SAFE_FREE(types);
|
||||
talloc_free(mem_ctx);
|
||||
return EINVAL;
|
||||
}
|
||||
tkt_checksum_idx = i;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
@ -471,6 +506,131 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Resign (and reform, including possibly new groups) a PAC */
|
||||
|
||||
static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
|
||||
const krb5_principal client_principal,
|
||||
const krb5_principal delegated_proxy_principal,
|
||||
struct hdb_entry_ex *client,
|
||||
struct hdb_entry_ex *server,
|
||||
struct hdb_entry_ex *krbtgt,
|
||||
krb5_pac *pac)
|
||||
{
|
||||
struct samba_kdc_entry *krbtgt_skdc_entry =
|
||||
talloc_get_type_abort(krbtgt->ctx,
|
||||
struct samba_kdc_entry);
|
||||
krb5_error_code ret;
|
||||
krb5_cksumtype ctype = CKSUMTYPE_NONE;
|
||||
struct hdb_entry_ex signing_krbtgt_hdb;
|
||||
|
||||
if (delegated_proxy_principal) {
|
||||
uint16_t rodc_id;
|
||||
unsigned int my_krbtgt_number;
|
||||
|
||||
/*
|
||||
* We're using delegated_proxy_principal for the moment to
|
||||
* indicate cases where the ticket was encrypted with the server
|
||||
* key, and not a krbtgt key. This cannot be trusted, so we need
|
||||
* to find a krbtgt key that signs the PAC in order to trust the
|
||||
* ticket.
|
||||
*
|
||||
* The krbtgt passed in to this function refers to the krbtgt
|
||||
* used to decrypt the ticket of the server requesting
|
||||
* S4U2Proxy.
|
||||
*
|
||||
* When we implement service ticket renewal, we need to check
|
||||
* the PAC, and this will need to be updated.
|
||||
*/
|
||||
ret = krb5_pac_get_kdc_checksum_info(context,
|
||||
*pac,
|
||||
&ctype,
|
||||
&rodc_id);
|
||||
if (ret != 0) {
|
||||
DEBUG(1, ("Failed to get PAC checksum info\n"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to check the KDC and ticket signatures, fetching the
|
||||
* correct key based on the enctype.
|
||||
*/
|
||||
|
||||
my_krbtgt_number = krbtgt_skdc_entry->kdc_db_ctx->my_krbtgt_number;
|
||||
|
||||
if (my_krbtgt_number != 0) {
|
||||
/*
|
||||
* If we are an RODC, and we are not the KDC that signed
|
||||
* the evidence ticket, then we need to proxy the
|
||||
* request.
|
||||
*/
|
||||
if (rodc_id != my_krbtgt_number) {
|
||||
return HDB_ERR_NOT_FOUND_HERE;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If we are a DC, the ticket may have been signed by a
|
||||
* different KDC than the one that issued the header
|
||||
* ticket.
|
||||
*/
|
||||
if (rodc_id != krbtgt->entry.kvno >> 16) {
|
||||
struct sdb_entry_ex signing_krbtgt_sdb;
|
||||
|
||||
/*
|
||||
* If we didn't sign the ticket, then return an
|
||||
* error.
|
||||
*/
|
||||
if (rodc_id != 0) {
|
||||
return KRB5KRB_AP_ERR_MODIFIED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch our key from the database. To support
|
||||
* key rollover, we're going to need to try
|
||||
* multiple keys by trial and error. For now,
|
||||
* krbtgt keys aren't assumed to change.
|
||||
*/
|
||||
ret = samba_kdc_fetch(context,
|
||||
krbtgt_skdc_entry->kdc_db_ctx,
|
||||
krbtgt->entry.principal,
|
||||
SDB_F_GET_KRBTGT | SDB_F_CANON,
|
||||
0,
|
||||
&signing_krbtgt_sdb);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdb_entry_ex_to_hdb_entry_ex(context,
|
||||
&signing_krbtgt_sdb,
|
||||
&signing_krbtgt_hdb);
|
||||
sdb_free_entry(&signing_krbtgt_sdb);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace the krbtgt entry with our own entry
|
||||
* for further processing.
|
||||
*/
|
||||
krbtgt = &signing_krbtgt_hdb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = samba_wdc_reget_pac2(context,
|
||||
delegated_proxy_principal,
|
||||
client,
|
||||
server,
|
||||
krbtgt,
|
||||
pac,
|
||||
ctype);
|
||||
|
||||
if (krbtgt == &signing_krbtgt_hdb) {
|
||||
hdb_free_entry(context, &signing_krbtgt_hdb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *get_netbios_name(TALLOC_CTX *mem_ctx, HostAddresses *addrs)
|
||||
{
|
||||
char *nb_name = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user