summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2022-11-01 15:20:47 +1300
committerStefan Metzmacher <metze@samba.org>2022-12-14 10:28:16 +0000
commita836bcf22ce87cf93e7d3cbf975d1baaa8f32c3b (patch)
tree39485da94b73b908c34655c84c02d099e4ad8ad0 /source4
parentda9da918f7510a1b8120479b8ec505b6b2397e93 (diff)
downloadsamba-a836bcf22ce87cf93e7d3cbf975d1baaa8f32c3b.tar.gz
CVE-2022-37966 kdc: Implement new Kerberos session key behaviour since ENC_HMAC_SHA1_96_AES256_SK was added
ENC_HMAC_SHA1_96_AES256_SK is a flag introduced for by Microsoft in this CVE to indicate that additionally, AES session keys are available. We set the etypes available for session keys depending on the encryption types that are supported by the principal. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15219 Pair-Programmed-With: Joseph Sutton <josephsutton@catalyst.net.nz> Signed-off-by: Andrew Bartlett <abartlet@samba.org> Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> Reviewed-by: Stefan Metzmacher <metze@samba.org> (similar to commit 975e43fc45531fdea14b93a3b1529b3218a177e6) [jsutton@samba.org Fixed knownfail conflicts] [jsutton@samba.org Adapted to older KDC code; fixed knownfail conflicts]
Diffstat (limited to 'source4')
-rw-r--r--source4/kdc/db-glue.c108
-rw-r--r--source4/kdc/sdb.c102
-rw-r--r--source4/kdc/sdb.h11
-rw-r--r--source4/kdc/sdb_to_hdb.c28
4 files changed, 235 insertions, 14 deletions
diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c
index 4af7a7303f7..ccf3951463b 100644
--- a/source4/kdc/db-glue.c
+++ b/source4/kdc/db-glue.c
@@ -753,7 +753,8 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
}
/* Set FAST support bits */
- *supported_enctypes_out |= supported_enctypes & (ENC_FAST_SUPPORTED |
+ *supported_enctypes_out |= supported_enctypes & (ENC_HMAC_SHA1_96_AES256_SK |
+ ENC_FAST_SUPPORTED |
ENC_COMPOUND_IDENTITY_SUPPORTED |
ENC_CLAIMS_SUPPORTED);
@@ -994,14 +995,19 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
bool is_rodc = false;
struct ldb_message_element *objectclasses;
struct ldb_val computer_val;
+ uint32_t default_supported_enctypes = lpcfg_kdc_default_domain_supported_enctypes(lp_ctx);
uint32_t supported_enctypes
= ldb_msg_find_attr_as_uint(msg,
"msDS-SupportedEncryptionTypes",
- 0);
+ default_supported_enctypes);
const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
computer_val.data = discard_const_p(uint8_t,"computer");
computer_val.length = strlen((const char *)computer_val.data);
+ if (supported_enctypes == 0) {
+ supported_enctypes = default_supported_enctypes;
+ }
+
if (ldb_msg_find_element(msg, "msDS-SecondaryKrbTgtNumber")) {
is_rodc = true;
}
@@ -1305,6 +1311,8 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
/* KDCs (and KDCs on RODCs) use AES */
supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
+ supported_enctypes &= ~ENC_HMAC_SHA1_96_AES256_SK;
+
enable_fast = lpcfg_kdc_enable_fast(kdc_db_ctx->lp_ctx);
if (enable_fast) {
supported_enctypes |= ENC_FAST_SUPPORTED;
@@ -1312,23 +1320,28 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
} else if (userAccountControl & (UF_PARTIAL_SECRETS_ACCOUNT|UF_SERVER_TRUST_ACCOUNT)) {
/* DCs and RODCs comptuer accounts use AES */
supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
+
+ supported_enctypes &= ~ENC_HMAC_SHA1_96_AES256_SK;
} else if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT ||
(ent_type == SAMBA_KDC_ENT_TYPE_ANY)) {
- /* for AS-REQ the client chooses the enc types it
+ /*
+ * for AS-REQ the client chooses the enc types it
* supports, and this will vary between computers a
- * user logs in from.
+ * user logs in from. Therefore, so that we accept any
+ * of the client's keys for decrypting padata,
+ * supported_enctypes should not restrict etype usage.
*
* likewise for 'any' return as much as is supported,
- * to export into a keytab */
- supported_enctypes = ENC_ALL_TYPES;
+ * to export into a keytab.
+ */
+ supported_enctypes |= ENC_ALL_TYPES;
}
+
+
/* If UF_USE_DES_KEY_ONLY has been set, then don't allow use of the newer enc types */
if (userAccountControl & UF_USE_DES_KEY_ONLY) {
- supported_enctypes = 0;
- } else {
- /* Otherwise, add in the default enc types */
- supported_enctypes |= ENC_RC4_HMAC_MD5;
+ supported_enctypes &= ~ENC_ALL_TYPES;
}
/* Get keys from the db */
@@ -1343,6 +1356,64 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context,
goto out;
}
+ ret = sdb_entry_set_etypes(&entry_ex->entry);
+ if (ret) {
+ goto out;
+ }
+
+ if (entry_ex->entry.flags.server) {
+ bool add_strong_aes_etypes =
+ supported_enctypes & KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK;
+ bool force_rc4 = lpcfg_kdc_force_enable_rc4_weak_session_keys(lp_ctx);
+ ret = sdb_entry_set_session_etypes(&entry_ex->entry,
+ add_strong_aes_etypes,
+ force_rc4);
+ if (ret) {
+ goto out;
+ }
+ }
+
+ if (entry_ex->entry.keys.len != 0) {
+ /*
+ * FIXME: Currently limited to Heimdal so as not to
+ * break MIT KDCs, for which no fix is available.
+ */
+#ifdef SAMBA4_USES_HEIMDAL
+ if (is_krbtgt) {
+ /*
+ * The krbtgt account, having no reason to
+ * issue tickets encrypted in weaker keys,
+ * shall only make available its strongest
+ * key. All weaker keys are stripped out. This
+ * makes it impossible for an RC4-encrypted
+ * TGT to be accepted when AES KDC keys exist.
+ *
+ * This controls the ticket key and so the PAC
+ * signature algorithms indirectly, preventing
+ * a weak KDC checksum from being accepted
+ * when we verify the signatures for an
+ * S4U2Proxy evidence ticket. As such, this is
+ * indispensable for addressing
+ * CVE-2022-37966.
+ *
+ * Being strict here also provides protection
+ * against possible future attacks on weak
+ * keys.
+ */
+ entry_ex->entry.keys.len = 1;
+ if (entry_ex->entry.etypes != NULL) {
+ entry_ex->entry.etypes->len = 1;
+ }
+ }
+#endif
+ } else {
+ /*
+ * oh, no password. Apparently (comment in
+ * hdb-ldap.c) this violates the ASN.1, but this
+ * allows an entry with no keys (yet).
+ */
+ }
+
p->msg = talloc_steal(p, msg);
p->supported_enctypes = supported_enctypes;
@@ -1767,6 +1838,23 @@ static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
goto out;
}
+ ret = sdb_entry_set_etypes(&entry_ex->entry);
+ if (ret) {
+ goto out;
+ }
+
+ {
+ bool add_strong_aes_etypes =
+ supported_enctypes & KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK;
+ bool force_rc4 = lpcfg_kdc_force_enable_rc4_weak_session_keys(lp_ctx);
+ ret = sdb_entry_set_session_etypes(&entry_ex->entry,
+ add_strong_aes_etypes,
+ force_rc4);
+ if (ret) {
+ goto out;
+ }
+ }
+
p->msg = talloc_steal(p, msg);
out:
diff --git a/source4/kdc/sdb.c b/source4/kdc/sdb.c
index 2150150505b..00e70c79faa 100644
--- a/source4/kdc/sdb.c
+++ b/source4/kdc/sdb.c
@@ -123,3 +123,105 @@ struct SDBFlags int2SDBFlags(unsigned n)
flags.do_not_store = (n >> 31) & 1;
return flags;
}
+
+/* Set the etypes of an sdb_entry based on its available current keys. */
+krb5_error_code sdb_entry_set_etypes(struct sdb_entry *s)
+{
+ if (s->keys.val != NULL) {
+ unsigned i;
+
+ s->etypes = malloc(sizeof(*s->etypes));
+ if (s->etypes == NULL) {
+ return ENOMEM;
+ }
+
+ s->etypes->len = s->keys.len;
+
+ s->etypes->val = calloc(s->etypes->len, sizeof(*s->etypes->val));
+ if (s->etypes->val == NULL) {
+ return ENOMEM;
+ }
+
+ for (i = 0; i < s->etypes->len; i++) {
+ const struct sdb_key *k = &s->keys.val[i];
+
+ s->etypes->val[i] = KRB5_KEY_TYPE(&(k->key));
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Set the session etypes of a server sdb_entry based on its etypes, forcing in
+ * strong etypes as desired.
+ */
+krb5_error_code sdb_entry_set_session_etypes(struct sdb_entry *s,
+ bool add_strong_aes_etypes,
+ bool force_rc4)
+{
+ if (s->etypes != NULL) {
+ unsigned i;
+ unsigned j = 0;
+ unsigned len = s->etypes->len;
+
+ s->session_etypes = malloc(sizeof(*s->session_etypes));
+ if (s->session_etypes == NULL) {
+ return ENOMEM;
+ }
+
+ if (add_strong_aes_etypes) {
+ /* Reserve space for AES256 and AES128. */
+ len += 2;
+ }
+
+ if (force_rc4) {
+ /* Reserve space for RC4. */
+ len += 1;
+ }
+
+ /* session_etypes must be sorted in order of strength, with preferred etype first. */
+
+ s->session_etypes->val = calloc(len, sizeof(*s->session_etypes->val));
+ if (s->session_etypes->val == NULL) {
+ return ENOMEM;
+ }
+
+ if (add_strong_aes_etypes) {
+ /* Add AES256 and AES128. */
+ s->session_etypes->val[j++] = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+ s->session_etypes->val[j++] = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+ }
+
+ if (force_rc4) {
+ /* Add RC4. */
+ s->session_etypes->val[j++] = ENCTYPE_ARCFOUR_HMAC;
+ }
+
+ for (i = 0; i < s->etypes->len; ++i) {
+ const krb5_enctype etype = s->etypes->val[i];
+
+ if (add_strong_aes_etypes &&
+ (etype == ENCTYPE_AES256_CTS_HMAC_SHA1_96 ||
+ etype == ENCTYPE_AES128_CTS_HMAC_SHA1_96))
+ {
+ /*
+ * Skip AES256 and AES128, for we've
+ * already added them.
+ */
+ continue;
+ }
+
+ if (force_rc4 && etype == ENCTYPE_ARCFOUR_HMAC) {
+ /* Skip RC4, for we've already added it. */
+ continue;
+ }
+
+ s->session_etypes->val[j++] = etype;
+ }
+
+ s->session_etypes->len = j;
+ }
+
+ return 0;
+}
diff --git a/source4/kdc/sdb.h b/source4/kdc/sdb.h
index cf7060bd169..2259278c8ae 100644
--- a/source4/kdc/sdb.h
+++ b/source4/kdc/sdb.h
@@ -45,6 +45,11 @@ struct sdb_event {
time_t time;
};
+struct sdb_etypes {
+ unsigned len;
+ krb5_enctype *val;
+};
+
struct SDBFlags {
unsigned int initial:1;
unsigned int forwardable:1;
@@ -84,6 +89,8 @@ struct sdb_entry {
krb5_principal principal;
unsigned int kvno;
struct sdb_keys keys;
+ struct sdb_etypes *etypes;
+ struct sdb_etypes *session_etypes;
struct sdb_event created_by;
struct sdb_event *modified_by;
time_t *valid_start;
@@ -133,5 +140,9 @@ struct sdb_entry_ex {
void sdb_free_entry(struct sdb_entry_ex *e);
void free_sdb_entry(struct sdb_entry *s);
struct SDBFlags int2SDBFlags(unsigned n);
+krb5_error_code sdb_entry_set_etypes(struct sdb_entry *s);
+krb5_error_code sdb_entry_set_session_etypes(struct sdb_entry *s,
+ bool add_strong_aes_etypes,
+ bool force_rc4);
#endif /* _KDC_SDB_H_ */
diff --git a/source4/kdc/sdb_to_hdb.c b/source4/kdc/sdb_to_hdb.c
index e2d6e40c837..f7904084bc5 100644
--- a/source4/kdc/sdb_to_hdb.c
+++ b/source4/kdc/sdb_to_hdb.c
@@ -26,6 +26,7 @@
#include "sdb.h"
#include "sdb_hdb.h"
#include "lib/krb5_wrap/krb5_samba.h"
+#include "librpc/gen_ndr/security.h"
#include "kdc/samba_kdc.h"
static void sdb_flags_to_hdb_flags(const struct SDBFlags *s,
@@ -276,14 +277,14 @@ static int sdb_entry_to_hdb_entry(krb5_context context,
sdb_flags_to_hdb_flags(&s->flags, &h->flags);
h->etypes = NULL;
- if (h->keys.val != NULL) {
+ if (s->etypes != NULL) {
h->etypes = malloc(sizeof(*h->etypes));
if (h->etypes == NULL) {
rc = ENOMEM;
goto error;
}
- h->etypes->len = s->keys.len;
+ h->etypes->len = s->etypes->len;
h->etypes->val = calloc(h->etypes->len, sizeof(int));
if (h->etypes->val == NULL) {
@@ -292,9 +293,28 @@ static int sdb_entry_to_hdb_entry(krb5_context context,
}
for (i = 0; i < h->etypes->len; i++) {
- Key k = h->keys.val[i];
+ h->etypes->val[i] = s->etypes->val[i];
+ }
+ }
+
+ h->session_etypes = NULL;
+ if (s->session_etypes != NULL) {
+ h->session_etypes = malloc(sizeof(*h->session_etypes));
+ if (h->session_etypes == NULL) {
+ rc = ENOMEM;
+ goto error;
+ }
+
+ h->session_etypes->len = s->session_etypes->len;
+
+ h->session_etypes->val = calloc(h->session_etypes->len, sizeof(*h->session_etypes->val));
+ if (h->session_etypes->val == NULL) {
+ rc = ENOMEM;
+ goto error;
+ }
- h->etypes->val[i] = KRB5_KEY_TYPE(&(k.key));
+ for (i = 0; i < h->session_etypes->len; ++i) {
+ h->session_etypes->val[i] = s->session_etypes->val[i];
}
}