From 7e2b114016b8abca66a973cd8e5603c47c976ebb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Nov 2017 11:57:08 +0100 Subject: [PATCH 1/5] HEIMDAL:kdc: let _kdc_encode_reply() use the encryption type based on the server key Currently the value is the same anyway as the session key is always of the same type as server key up to now, but that will change shortly. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13135 Signed-off-by: Stefan Metzmacher --- source4/heimdal/kdc/kerberos5.c | 5 ++--- source4/heimdal/kdc/krb5tgs.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index 4baf90e..366a545 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -322,7 +322,6 @@ krb5_error_code _kdc_encode_reply(krb5_context context, krb5_kdc_configuration *config, KDC_REP *rep, const EncTicketPart *et, EncKDCRepPart *ek, - krb5_enctype etype, int skvno, const EncryptionKey *skey, int ckvno, const EncryptionKey *reply_key, int rk_is_subkey, @@ -349,7 +348,7 @@ _kdc_encode_reply(krb5_context context, return KRB5KRB_ERR_GENERIC; } - ret = krb5_crypto_init(context, skey, etype, &crypto); + ret = krb5_crypto_init(context, skey, 0, &crypto); if (ret) { const char *msg; free(buf); @@ -1751,7 +1750,7 @@ _kdc_as_rep(krb5_context context, log_as_req(context, config, reply_key->keytype, setype, b); ret = _kdc_encode_reply(context, config, - &rep, &et, &ek, setype, server->entry.kvno, + &rep, &et, &ek, server->entry.kvno, &skey->key, client->entry.kvno, reply_key, 0, &e_text, reply); free_EncTicketPart(&et); diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index 5033a24..05fd321 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -988,7 +988,7 @@ tgs_make_reply(krb5_context context, etype list, even if we don't want a session key with DES3? */ ret = _kdc_encode_reply(context, config, - &rep, &et, &ek, et.key.keytype, + &rep, &et, &ek, kvno, serverkey, 0, replykey, rk_is_subkey, e_text, reply); -- 1.9.1 From 95d9003b6283f61dd4867c849d2efa89264c34e5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Nov 2017 15:47:25 +0100 Subject: [PATCH 2/5] HEIMDAL:hdb: export a hdb_enctype_supported() helper function BUG: https://bugzilla.samba.org/show_bug.cgi?id=13135 Signed-off-by: Stefan Metzmacher --- source4/heimdal/kdc/kerberos5.c | 15 ++++++++++----- source4/heimdal/kdc/krb5tgs.c | 3 +-- source4/heimdal/lib/hdb/hdb.c | 30 +++++++++++++++++++++++++++--- source4/heimdal/lib/hdb/version-script.map | 1 + 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index 366a545..5118d8e 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -131,7 +131,7 @@ _kdc_find_etype(krb5_context context, krb5_boolean use_strongest_session_key, krb5_error_code ret; krb5_salt def_salt; krb5_enctype enctype = ETYPE_NULL; - Key *key; + Key *key = NULL; int i; /* We'll want to avoid keys with v4 salted keys in the pre-auth case... */ @@ -159,29 +159,34 @@ _kdc_find_etype(krb5_context context, krb5_boolean use_strongest_session_key, /* drive the search with local supported enctypes list */ p = krb5_kerberos_enctypes(context); - for (i = 0; p[i] != ETYPE_NULL && enctype == ETYPE_NULL; i++) { + for (i = 0; p[i] != ETYPE_NULL && key == NULL; i++) { if (krb5_enctype_valid(context, p[i]) != 0) continue; /* check that the client supports it too */ - for (j = 0; j < len && enctype == ETYPE_NULL; j++) { + for (j = 0; j < len && key == NULL; j++) { if (p[i] != etypes[j]) continue; /* save best of union of { client, crypto system } */ if (clientbest == ETYPE_NULL) clientbest = p[i]; + if (enctype == ETYPE_NULL) { + ret = hdb_enctype_supported(context, &princ->entry, p[i]); + if (ret == 0) { + enctype = p[i]; + } + } /* check target princ support */ ret = hdb_enctype2key(context, &princ->entry, p[i], &key); if (ret) continue; if (is_preauth && !is_default_salt_p(&def_salt, key)) continue; - enctype = p[i]; } } if (clientbest != ETYPE_NULL && enctype == ETYPE_NULL) enctype = clientbest; - else if (enctype == ETYPE_NULL) + else if (key == NULL) ret = KRB5KDC_ERR_ETYPE_NOSUPP; if (ret == 0 && ret_enctype != NULL) *ret_enctype = enctype; diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index 05fd321..e11ad52 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -1705,7 +1705,7 @@ server_lookup: ret = _kdc_find_etype(context, config->tgs_use_strongest_session_key, FALSE, - server, b->etype.val, b->etype.len, NULL, + server, b->etype.val, b->etype.len, &etype, &skey); if(ret) { kdc_log(context, config, 0, @@ -1713,7 +1713,6 @@ server_lookup: goto out; } ekey = &skey->key; - etype = skey->key.keytype; kvno = server->entry.kvno; } diff --git a/source4/heimdal/lib/hdb/hdb.c b/source4/heimdal/lib/hdb/hdb.c index 5dc5a09..4c8df93 100644 --- a/source4/heimdal/lib/hdb/hdb.c +++ b/source4/heimdal/lib/hdb/hdb.c @@ -93,11 +93,12 @@ static struct hdb_method dbmetod = #endif -krb5_error_code -hdb_next_enctype2key(krb5_context context, +static krb5_error_code +_hdb_next_enctype2key(krb5_context context, const hdb_entry *e, krb5_enctype enctype, - Key **key) + Key **key, + bool require_key) { Key *k; @@ -105,6 +106,10 @@ hdb_next_enctype2key(krb5_context context, k < e->keys.val + e->keys.len; k++) { + if (require_key && k->key.keyvalue.length == 0) { + continue; + } + if(k->key.keytype == enctype){ *key = k; return 0; @@ -116,6 +121,16 @@ hdb_next_enctype2key(krb5_context context, return KRB5_PROG_ETYPE_NOSUPP; /* XXX */ } + +krb5_error_code +hdb_next_enctype2key(krb5_context context, + const hdb_entry *e, + krb5_enctype enctype, + Key **key) +{ + return _hdb_next_enctype2key(context, e, enctype, key, true); +} + krb5_error_code hdb_enctype2key(krb5_context context, hdb_entry *e, @@ -126,6 +141,15 @@ hdb_enctype2key(krb5_context context, return hdb_next_enctype2key(context, e, enctype, key); } +krb5_error_code +hdb_enctype_supported(krb5_context context, + hdb_entry *e, + krb5_enctype enctype) +{ + Key *key = NULL; + return _hdb_next_enctype2key(context, e, enctype, &key, false); +} + void hdb_free_key(Key *key) { diff --git a/source4/heimdal/lib/hdb/version-script.map b/source4/heimdal/lib/hdb/version-script.map index f80fb78..c4bd8f4 100644 --- a/source4/heimdal/lib/hdb/version-script.map +++ b/source4/heimdal/lib/hdb/version-script.map @@ -20,6 +20,7 @@ HEIMDAL_HDB_1.0 { hdb_dbinfo_get_realm; hdb_default_db; hdb_enctype2key; + hdb_enctype_supported; hdb_entry2string; hdb_entry2value; hdb_entry_alias2value; -- 1.9.1 From 835b960cc6dc0ceb3aa007718fb5fab85f881a7a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Nov 2017 18:03:45 +0100 Subject: [PATCH 3/5] s4:kdc: use the strongest possible tgs session key BUG: https://bugzilla.samba.org/show_bug.cgi?id=13135 Signed-off-by: Stefan Metzmacher --- source4/kdc/kdc-heimdal.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source4/kdc/kdc-heimdal.c b/source4/kdc/kdc-heimdal.c index d5c721b..883158d 100644 --- a/source4/kdc/kdc-heimdal.c +++ b/source4/kdc/kdc-heimdal.c @@ -373,10 +373,14 @@ static void kdc_task_init(struct task_server *task) * * The old behavior in the _kdc_get_preferred_key() * function is use_strongest_server_key=TRUE. + * + * We actually want the behavior of + * tgs_use_strongest_session_key=TRUE, + * see https://bugzilla.samba.org/show_bug.cgi?id=13135 */ kdc_config->as_use_strongest_session_key = false; kdc_config->preauth_use_strongest_session_key = false; - kdc_config->tgs_use_strongest_session_key = false; + kdc_config->tgs_use_strongest_session_key = true; kdc_config->use_strongest_server_key = true; kdc_config->autodetect_referrals = false; -- 1.9.1 From 28b89388522f387ac60db7d95972ec75fde0de5c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Nov 2017 12:23:31 +0100 Subject: [PATCH 4/5] TODO s4:kdc: msDS-SupportedEncryptionTypes only on computers BUG: https://bugzilla.samba.org/show_bug.cgi?id=13135 --- source4/kdc/db-glue.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c index 9ac5a1d..0480009 100644 --- a/source4/kdc/db-glue.c +++ b/source4/kdc/db-glue.c @@ -337,6 +337,14 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context, "msDS-SupportedEncryptionTypes", 0); + if (userAccountControl & UF_NORMAL_ACCOUNT) { + supported_enctypes = 0; + } + if (supported_enctypes == 0) { + /* Otherwise, add in the default enc types */ + supported_enctypes |= ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5; + } + if (rid == DOMAIN_RID_KRBTGT || is_rodc) { /* KDCs (and KDCs on RODCs) use AES */ supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256; @@ -357,7 +365,7 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context, /* 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 = ENC_CRC32|ENC_RSA_MD5; - } else { + } else if (supported_enctypes == 0) { /* Otherwise, add in the default enc types */ supported_enctypes |= ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5; } -- 1.9.1 From aa54bb1f6eca4460feea918e32fc675703dee004 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Nov 2017 12:23:31 +0100 Subject: [PATCH 5/5] TODO s4:kdc: indicate support for new encryption types by adding empty keys BUG: https://bugzilla.samba.org/show_bug.cgi?id=13135 --- source4/kdc/db-glue.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c index 0480009..bd78c15 100644 --- a/source4/kdc/db-glue.c +++ b/source4/kdc/db-glue.c @@ -316,6 +316,7 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context, bool is_rodc, uint32_t userAccountControl, enum samba_kdc_ent_type ent_type, + unsigned flags, struct sdb_entry_ex *entry_ex) { krb5_error_code ret = 0; @@ -336,6 +337,30 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context, = ldb_msg_find_attr_as_uint(msg, "msDS-SupportedEncryptionTypes", 0); + uint32_t new_session_enctypes = 0; + const krb5_enctype newer_enctypes[] = { + ENCTYPE_AES256_CTS_HMAC_SHA1_96, + ENCTYPE_AES128_CTS_HMAC_SHA1_96, + }; + + switch (ent_type) { + case SAMBA_KDC_ENT_TYPE_CLIENT: + case SAMBA_KDC_ENT_TYPE_ANY: + break; + case SAMBA_KDC_ENT_TYPE_SERVER: + case SAMBA_KDC_ENT_TYPE_KRBTGT: + case SAMBA_KDC_ENT_TYPE_TRUST: + if (flags & (SDB_F_FOR_AS_REQ|SDB_F_FOR_TGS_REQ)) { + /* + * We should indicate support for new encryption + * types (for session keys) via empty keyvalues, + * in case we don't have stored keys for such encryption + * types. + */ + new_session_enctypes = supported_enctypes; + } + break; + } if (userAccountControl & UF_NORMAL_ACCOUNT) { supported_enctypes = 0; @@ -572,6 +597,8 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context, return 0; } + allocated_keys += ARRAY_SIZE(newer_enctypes); + /* allocate space to decode into */ entry_ex->entry.keys.len = 0; entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(struct sdb_key)); @@ -599,12 +626,15 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context, if (pkb4) { for (i=0; i < pkb4->num_keys; i++) { struct sdb_key key = {}; + uint32_t enctype; if (!pkb4->keys[i].value) continue; - if (!(kerberos_enctype_to_bitmap(pkb4->keys[i].keytype) & supported_enctypes)) { + enctype = kerberos_enctype_to_bitmap(pkb4->keys[i].keytype); + if (!(enctype & supported_enctypes)) { continue; } + new_session_enctypes &= ~enctype; if (pkb4->salt.string) { DATA_BLOB salt; @@ -657,12 +687,15 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context, } else if (pkb3) { for (i=0; i < pkb3->num_keys; i++) { struct sdb_key key = {}; + uint32_t enctype; if (!pkb3->keys[i].value) continue; - if (!(kerberos_enctype_to_bitmap(pkb3->keys[i].keytype) & supported_enctypes)) { + enctype = kerberos_enctype_to_bitmap(pkb3->keys[i].keytype); + if (!(enctype & supported_enctypes)) { continue; } + new_session_enctypes &= ~enctype; if (pkb3->salt.string) { DATA_BLOB salt; @@ -706,6 +739,30 @@ static krb5_error_code samba_kdc_message2entry_keys(krb5_context context, } } + /* + * Check if we should announce support for newer encryption + * types, which can be used as session keys, while the + * last password change only stored older keys. + * + * We do that by providing entries with empty key values. + */ + for (i = 0; i < ARRAY_SIZE(newer_enctypes); i++) { + struct sdb_key key = { + .key = { + .keytype = newer_enctypes[i], + }, + }; + uint32_t enctype; + + enctype = kerberos_enctype_to_bitmap(key.key.keytype); + if (!(enctype & new_session_enctypes)) { + continue; + } + + entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key; + entry_ex->entry.keys.len++; + } + out: if (ret != 0) { entry_ex->entry.keys.len = 0; @@ -1139,7 +1196,7 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context, /* Get keys from the db */ ret = samba_kdc_message2entry_keys(context, kdc_db_ctx, p, msg, rid, is_rodc, userAccountControl, - ent_type, entry_ex); + ent_type, flags, entry_ex); if (ret) { /* Could be bogus data in the entry, or out of memory */ goto out; -- 1.9.1