Compare commits

...

No commits in common. 'c9' and 'c8' have entirely different histories.
c9 ... c8

3
.gitignore vendored

@ -1 +1,2 @@
SOURCES/krb5-1.21.1.tar.gz
SOURCES/krb5-1.18.2-pdfs.tar
SOURCES/krb5-1.18.2.tar.gz

@ -1 +1,2 @@
505440658a00e009c430439dba60e13a98067cd3 SOURCES/krb5-1.21.1.tar.gz
db930a6653503c36027a4f65d761f8838c7636ae SOURCES/krb5-1.18.2-pdfs.tar
547c4e4afa06dd39c888a9ee89397ec3c3425c90 SOURCES/krb5-1.18.2.tar.gz

@ -1,310 +0,0 @@
From 93bb4f5ba6fd79e72a75de20e209db219118a3a1 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 2 Aug 2023 10:19:28 +0200
Subject: [PATCH] [downstream] Revert "Don't issue session keys with deprecated
enctypes"
This reverts commit 1b57a4d134bbd0e7c52d5885a92eccc815726463.
---
doc/admin/conf_files/krb5_conf.rst | 12 ------------
doc/admin/enctypes.rst | 23 +++-------------------
src/include/k5-int.h | 4 ----
src/kdc/kdc_util.c | 10 ----------
src/lib/krb5/krb/get_in_tkt.c | 31 +++++++++++-------------------
src/lib/krb5/krb/init_ctx.c | 10 ----------
src/tests/gssapi/t_enctypes.py | 3 +--
src/tests/t_etype_info.py | 2 +-
src/tests/t_sesskeynego.py | 28 ++-------------------------
src/util/k5test.py | 4 ++--
10 files changed, 20 insertions(+), 107 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index ecdf917501..f22d5db11b 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -95,18 +95,6 @@ Additionally, krb5.conf may include any of the relations described in
The libdefaults section may contain any of the following relations:
-**allow_des3**
- Permit the KDC to issue tickets with des3-cbc-sha1 session keys.
- In future releases, this flag will allow des3-cbc-sha1 to be used
- at all. The default value for this tag is false. (Added in
- release 1.21.)
-
-**allow_rc4**
- Permit the KDC to issue tickets with arcfour-hmac session keys.
- In future releases, this flag will allow arcfour-hmac to be used
- at all. The default value for this tag is false. (Added in
- release 1.21.)
-
**allow_weak_crypto**
If this flag is set to false, then weak encryption types (as noted
in :ref:`Encryption_types` in :ref:`kdc.conf(5)`) will be filtered
diff --git a/doc/admin/enctypes.rst b/doc/admin/enctypes.rst
index dce19ad43e..694922c0d9 100644
--- a/doc/admin/enctypes.rst
+++ b/doc/admin/enctypes.rst
@@ -48,15 +48,12 @@ Session key selection
The KDC chooses the session key enctype by taking the intersection of
its **permitted_enctypes** list, the list of long-term keys for the
most recent kvno of the service, and the client's requested list of
-enctypes. Starting in krb5-1.21, all services are assumed to support
-aes256-cts-hmac-sha1-96; also, des3-cbc-sha1 and arcfour-hmac session
-keys will not be issued by default.
+enctypes.
Starting in krb5-1.11, it is possible to set a string attribute on a
service principal to control what session key enctypes the KDC may
-issue for service tickets for that principal, overriding the service's
-long-term keys and the assumption of aes256-cts-hmac-sha1-96 support.
-See :ref:`set_string` in :ref:`kadmin(1)` for details.
+issue for service tickets for that principal. See :ref:`set_string`
+in :ref:`kadmin(1)` for details.
Choosing enctypes for a service
@@ -90,20 +87,6 @@ affect how enctypes are chosen.
acceptable risk for your environment and the weak enctypes are
required for backward compatibility.
-**allow_des3**
- was added in release 1.21 and defaults to *false*. Unless this
- flag is set to *true*, the KDC will not issue tickets with
- des3-cbc-sha1 session keys. In a future release, this flag will
- control whether des3-cbc-sha1 is permitted in similar fashion to
- weak enctypes.
-
-**allow_rc4**
- was added in release 1.21 and defaults to *false*. Unless this
- flag is set to *true*, the KDC will not issue tickets with
- arcfour-hmac session keys. In a future release, this flag will
- control whether arcfour-hmac is permitted in similar fashion to
- weak enctypes.
-
**permitted_enctypes**
controls the set of enctypes that a service will permit for
session keys and for ticket and authenticator encryption. The KDC
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 2f7791b775..1d1c8293f4 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -180,8 +180,6 @@ typedef unsigned char u_char;
* matches the variable name. Keep these alphabetized. */
#define KRB5_CONF_ACL_FILE "acl_file"
#define KRB5_CONF_ADMIN_SERVER "admin_server"
-#define KRB5_CONF_ALLOW_DES3 "allow_des3"
-#define KRB5_CONF_ALLOW_RC4 "allow_rc4"
#define KRB5_CONF_ALLOW_WEAK_CRYPTO "allow_weak_crypto"
#define KRB5_CONF_AUTH_TO_LOCAL "auth_to_local"
#define KRB5_CONF_AUTH_TO_LOCAL_NAMES "auth_to_local_names"
@@ -1240,8 +1238,6 @@ struct _krb5_context {
struct _kdb_log_context *kdblog_context;
krb5_boolean allow_weak_crypto;
- krb5_boolean allow_des3;
- krb5_boolean allow_rc4;
krb5_boolean ignore_acceptor_hostname;
krb5_boolean enforce_ok_as_delegate;
enum dns_canonhost dns_canonicalize_hostname;
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index e54cc751f9..75e04b73db 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -1088,16 +1088,6 @@ select_session_keytype(krb5_context context, krb5_db_entry *server,
if (!krb5_is_permitted_enctype(context, ktype[i]))
continue;
- /*
- * Prevent these deprecated enctypes from being used as session keys
- * unless they are explicitly allowed. In the future they will be more
- * comprehensively disabled and eventually removed.
- */
- if (ktype[i] == ENCTYPE_DES3_CBC_SHA1 && !context->allow_des3)
- continue;
- if (ktype[i] == ENCTYPE_ARCFOUR_HMAC && !context->allow_rc4)
- continue;
-
if (dbentry_supports_enctype(context, server, ktype[i]))
return ktype[i];
}
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index ea089f0fcc..1b420a3ac2 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -1582,31 +1582,22 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
(*prompter)(context, data, 0, banner, 0, 0);
}
-/* Display a warning via the prompter if a deprecated enctype was used for
- * either the reply key or the session key. */
+/* Display a warning via the prompter if des3-cbc-sha1 was used for either the
+ * reply key or the session key. */
static void
-warn_deprecated(krb5_context context, krb5_init_creds_context ctx,
- krb5_enctype as_key_enctype)
+warn_des3(krb5_context context, krb5_init_creds_context ctx,
+ krb5_enctype as_key_enctype)
{
- krb5_enctype etype;
- char encbuf[128], banner[256];
+ const char *banner;
- if (ctx->prompter == NULL)
- return;
-
- if (krb5int_c_deprecated_enctype(as_key_enctype))
- etype = as_key_enctype;
- else if (krb5int_c_deprecated_enctype(ctx->cred.keyblock.enctype))
- etype = ctx->cred.keyblock.enctype;
- else
+ if (as_key_enctype != ENCTYPE_DES3_CBC_SHA1 &&
+ ctx->cred.keyblock.enctype != ENCTYPE_DES3_CBC_SHA1)
return;
-
- if (krb5_enctype_to_name(etype, FALSE, encbuf, sizeof(encbuf)) != 0)
+ if (ctx->prompter == NULL)
return;
- snprintf(banner, sizeof(banner),
- _("Warning: encryption type %s used for authentication is "
- "deprecated and will be disabled"), encbuf);
+ banner = _("Warning: encryption type des3-cbc-sha1 used for "
+ "authentication is weak and will be disabled");
/* PROMPTER_INVOCATION */
(*ctx->prompter)(context, ctx->prompter_data, NULL, banner, 0, NULL);
}
@@ -1857,7 +1848,7 @@ init_creds_step_reply(krb5_context context,
ctx->complete = TRUE;
warn_pw_expiry(context, ctx->opt, ctx->prompter, ctx->prompter_data,
ctx->in_tkt_service, ctx->reply);
- warn_deprecated(context, ctx, encrypting_key.enctype);
+ warn_des3(context, ctx, encrypting_key.enctype);
cleanup:
krb5_free_pa_data(context, kdc_padata);
diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
index a6c2bbeb54..87b486c53f 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -221,16 +221,6 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
goto cleanup;
ctx->allow_weak_crypto = tmp;
- retval = get_boolean(ctx, KRB5_CONF_ALLOW_DES3, 0, &tmp);
- if (retval)
- goto cleanup;
- ctx->allow_des3 = tmp;
-
- retval = get_boolean(ctx, KRB5_CONF_ALLOW_RC4, 0, &tmp);
- if (retval)
- goto cleanup;
- ctx->allow_rc4 = tmp;
-
retval = get_boolean(ctx, KRB5_CONF_IGNORE_ACCEPTOR_HOSTNAME, 0, &tmp);
if (retval)
goto cleanup;
diff --git a/src/tests/gssapi/t_enctypes.py b/src/tests/gssapi/t_enctypes.py
index f5f11842e2..7494d7fcdb 100755
--- a/src/tests/gssapi/t_enctypes.py
+++ b/src/tests/gssapi/t_enctypes.py
@@ -18,8 +18,7 @@ d_rc4 = 'DEPRECATED:arcfour-hmac'
# These tests make assumptions about the default enctype lists, so set
# them explicitly rather than relying on the library defaults.
supp='aes256-cts:normal aes128-cts:normal des3-cbc-sha1:normal rc4-hmac:normal'
-conf = {'libdefaults': {'permitted_enctypes': 'aes des3 rc4',
- 'allow_des3': 'true', 'allow_rc4': 'true'},
+conf = {'libdefaults': {'permitted_enctypes': 'aes des3 rc4'},
'realms': {'$realm': {'supported_enctypes': supp}}}
realm = K5Realm(krb5_conf=conf)
shutil.copyfile(realm.ccache, os.path.join(realm.testdir, 'save'))
diff --git a/src/tests/t_etype_info.py b/src/tests/t_etype_info.py
index 38cf96ca8f..c982508d8b 100644
--- a/src/tests/t_etype_info.py
+++ b/src/tests/t_etype_info.py
@@ -1,7 +1,7 @@
from k5test import *
supported_enctypes = 'aes128-cts des3-cbc-sha1 rc4-hmac'
-conf = {'libdefaults': {'allow_des3': 'true', 'allow_rc4': 'true'},
+conf = {'libdefaults': {'allow_weak_crypto': 'true'},
'realms': {'$realm': {'supported_enctypes': supported_enctypes}}}
realm = K5Realm(create_host=False, get_creds=False, krb5_conf=conf)
diff --git a/src/tests/t_sesskeynego.py b/src/tests/t_sesskeynego.py
index 5a213617b5..9024aee838 100755
--- a/src/tests/t_sesskeynego.py
+++ b/src/tests/t_sesskeynego.py
@@ -25,8 +25,6 @@ conf3 = {'libdefaults': {
'default_tkt_enctypes': 'aes128-cts',
'default_tgs_enctypes': 'rc4-hmac,aes128-cts'}}
conf4 = {'libdefaults': {'permitted_enctypes': 'aes256-cts'}}
-conf5 = {'libdefaults': {'allow_rc4': 'true'}}
-conf6 = {'libdefaults': {'allow_des3': 'true'}}
# Test with client request and session_enctypes preferring aes128, but
# aes256 long-term key.
realm = K5Realm(krb5_conf=conf1, create_host=False, get_creds=False)
@@ -56,12 +54,10 @@ realm.run([kadminl, 'setstr', 'server', 'session_enctypes',
'aes128-cts,aes256-cts'])
test_kvno(realm, 'aes128-cts-hmac-sha1-96', 'aes256-cts-hmac-sha1-96')
-# 3b: Skip RC4 (as the KDC does not allow it for session keys by
-# default) and negotiate aes128-cts session key, with only an aes256
-# long-term service key.
+# 3b: Negotiate rc4-hmac session key when principal only has aes256 long-term.
realm.run([kadminl, 'setstr', 'server', 'session_enctypes',
'rc4-hmac,aes128-cts,aes256-cts'])
-test_kvno(realm, 'aes128-cts-hmac-sha1-96', 'aes256-cts-hmac-sha1-96')
+test_kvno(realm, 'DEPRECATED:arcfour-hmac', 'aes256-cts-hmac-sha1-96')
realm.stop()
# 4: Check that permitted_enctypes is a default for session key enctypes.
@@ -71,24 +67,4 @@ realm.run([kvno, 'user'],
expected_trace=('etypes requested in TGS request: aes256-cts',))
realm.stop()
-# 5: allow_rc4 permits negotiation of rc4-hmac session key.
-realm = K5Realm(krb5_conf=conf5, create_host=False, get_creds=False)
-realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts', 'server'])
-realm.run([kadminl, 'setstr', 'server', 'session_enctypes', 'rc4-hmac'])
-test_kvno(realm, 'DEPRECATED:arcfour-hmac', 'aes256-cts-hmac-sha1-96')
-realm.stop()
-
-# 6: allow_des3 permits negotiation of des3-cbc-sha1 session key.
-realm = K5Realm(krb5_conf=conf6, create_host=False, get_creds=False)
-realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts', 'server'])
-realm.run([kadminl, 'setstr', 'server', 'session_enctypes', 'des3-cbc-sha1'])
-test_kvno(realm, 'DEPRECATED:des3-cbc-sha1', 'aes256-cts-hmac-sha1-96')
-realm.stop()
-
-# 7: default config negotiates aes256-sha1 session key for RC4-only service.
-realm = K5Realm(create_host=False, get_creds=False)
-realm.run([kadminl, 'addprinc', '-randkey', '-e', 'rc4-hmac', 'server'])
-test_kvno(realm, 'aes256-cts-hmac-sha1-96', 'DEPRECATED:arcfour-hmac')
-realm.stop()
-
success('sesskeynego')
diff --git a/src/util/k5test.py b/src/util/k5test.py
index 8e5f5ba8e9..2a86c5cdfc 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -1340,14 +1340,14 @@ _passes = [
# Exercise the DES3 enctype.
('des3', None,
- {'libdefaults': {'permitted_enctypes': 'des3 aes256-sha1'}},
+ {'libdefaults': {'permitted_enctypes': 'des3'}},
{'realms': {'$realm': {
'supported_enctypes': 'des3-cbc-sha1:normal',
'master_key_type': 'des3-cbc-sha1'}}}),
# Exercise the arcfour enctype.
('arcfour', None,
- {'libdefaults': {'permitted_enctypes': 'rc4 aes256-sha1'}},
+ {'libdefaults': {'permitted_enctypes': 'rc4'}},
{'realms': {'$realm': {
'supported_enctypes': 'arcfour-hmac:normal',
'master_key_type': 'arcfour-hmac'}}}),
--
2.41.0

@ -1,81 +0,0 @@
From 343e4042abdec8697d2c30eb84f70bdbd8388302 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 5 May 2022 17:15:12 +0200
Subject: [PATCH] [downstream] Allow krad UDP/TCP localhost connection with FIPS
libkrad allows to establish connections only to UNIX socket in FIPS
mode, because MD5 digest is not considered safe enough to be used for
network communication. However, FreeRadius requires connection on TCP or
UDP ports.
This commit allows TCP or UDP connections in FIPS mode if destination is
localhost.
Resolves: rhbz#2082189
---
src/lib/krad/remote.c | 35 +++++++++++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
index 929f1cef67..063f17a613 100644
--- a/src/lib/krad/remote.c
+++ b/src/lib/krad/remote.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <unistd.h>
+#include <stdbool.h>
#include <sys/un.h>
@@ -74,6 +75,35 @@ on_io(verto_ctx *ctx, verto_ev *ev);
static void
on_timeout(verto_ctx *ctx, verto_ev *ev);
+static in_addr_t get_in_addr(struct addrinfo *info)
+{ return ((struct sockaddr_in *)(info->ai_addr))->sin_addr.s_addr; }
+
+static struct in6_addr *get_in6_addr(struct addrinfo *info)
+{ return &(((struct sockaddr_in6 *)(info->ai_addr))->sin6_addr); }
+
+static bool is_inet_localhost(struct addrinfo *info)
+{
+ struct addrinfo *p;
+
+ for (p = info; p; p = p->ai_next) {
+ switch (p->ai_family) {
+ case AF_INET:
+ if (IN_LOOPBACKNET != (get_in_addr(p) & IN_CLASSA_NET
+ >> IN_CLASSA_NSHIFT))
+ return false;
+ break;
+ case AF_INET6:
+ if (!IN6_IS_ADDR_LOOPBACK(get_in6_addr(p)))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
/* Iterate over the set of outstanding packets. */
static const krad_packet *
iterator(request **out)
@@ -460,8 +490,9 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
(krad_packet_iter_cb)iterator, &r, &tmp);
if (retval != 0)
goto error;
- else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL &&
- rr->info->ai_family != AF_UNIX) {
+ else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL
+ && rr->info->ai_family != AF_UNIX
+ && !is_inet_localhost(rr->info)) {
/* This would expose cleartext passwords, so abort. */
retval = ESOCKTNOSUPPORT;
goto error;
--
2.41.0

@ -1,41 +0,0 @@
From aa0556348373d6aca0a1bda96fe7a47888051d33 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 7 Dec 2022 13:22:42 +0100
Subject: [PATCH] [downstream] Make tests compatible with
sssd_krb5_locator_plugin.so
The sssd_krb5_locator_plugin.so plugin provided by sssd-client conflicts
with the upstream test t_discover_uri.py. The test has to be modified in
order to avoid false positive.
---
src/lib/krb5/os/t_discover_uri.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/lib/krb5/os/t_discover_uri.py b/src/lib/krb5/os/t_discover_uri.py
index 87bac17929..26bc95a8dc 100644
--- a/src/lib/krb5/os/t_discover_uri.py
+++ b/src/lib/krb5/os/t_discover_uri.py
@@ -1,3 +1,4 @@
+from os.path import exists
from k5test import *
entries = ('URI _kerberos.TEST krb5srv::kkdcp:https://kdc1 1 1\n',
@@ -37,8 +38,14 @@ realm.env['RESOLV_WRAPPER_HOSTS'] = hosts_filename
out = realm.run(['./t_locate_kdc', 'TEST'], env=realm.env)
l = out.splitlines()
+if (exists('/usr/lib/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so')
+ or exists('/usr/lib64/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so')):
+ line_range = range(6, 14)
+else:
+ line_range = range(4, 12)
+
j = 0
-for i in range(4, 12):
+for i in line_range:
if l[i].strip() != expected[j]:
fail('URI answers do not match')
j += 1
--
2.41.0

@ -1,120 +0,0 @@
From 52904f3693397dace4e9ef5db1cd7d14eaa3b1fb Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 5 Jan 2023 20:06:47 +0100
Subject: [PATCH] [downstream] Include missing OpenSSL FIPS header
The inclusion of openssl/fips.h, which provides the declaration of
FIPS_mode(), was removed from openssl/crypto.h. As a consequence, this
header file has to be included explicitly in krb5 code.
---
src/lib/crypto/krb/prng.c | 4 +++-
src/lib/crypto/openssl/enc_provider/camellia.c | 1 +
src/lib/crypto/openssl/enc_provider/rc4.c | 4 ++++
src/lib/crypto/openssl/hmac.c | 1 +
src/lib/krad/internal.h | 4 ++++
src/plugins/preauth/spake/spake_client.c | 4 ++++
src/plugins/preauth/spake/spake_kdc.c | 4 ++++
7 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c
index 9e80a03d21..ae37c77518 100644
--- a/src/lib/crypto/krb/prng.c
+++ b/src/lib/crypto/krb/prng.c
@@ -28,7 +28,9 @@
#include <openssl/rand.h>
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/fips.h>
+#else
#include <openssl/crypto.h>
#endif
diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
index d9f327add6..3dd3b0624f 100644
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
@@ -32,6 +32,7 @@
#include <openssl/camellia.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/core_names.h>
+#include <openssl/fips.h>
#else
#include <openssl/modes.h>
#endif
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
index ce63cb5f1b..6a83f10d27 100644
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
@@ -38,6 +38,10 @@
#include <openssl/evp.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/fips.h>
+#endif
+
/*
* The loopback field is a pointer to the structure. If the application copies
* the state (not a valid operation, but one which happens to works with some
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
index f21e268f7f..25a419d73a 100644
--- a/src/lib/crypto/openssl/hmac.c
+++ b/src/lib/crypto/openssl/hmac.c
@@ -59,6 +59,7 @@
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/params.h>
#include <openssl/core_names.h>
+#include <openssl/fips.h>
#else
#include <openssl/hmac.h>
#endif
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
index e123763954..a17b6f39b1 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -41,6 +41,10 @@
#include <openssl/crypto.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/fips.h>
+#endif
+
#ifndef UCHAR_MAX
#define UCHAR_MAX 255
#endif
diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
index a3ce22b70f..13c699071f 100644
--- a/src/plugins/preauth/spake/spake_client.c
+++ b/src/plugins/preauth/spake/spake_client.c
@@ -40,6 +40,10 @@
#include <openssl/crypto.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/fips.h>
+#endif
+
typedef struct reqstate_st {
krb5_pa_spake *msg; /* set in prep_questions, used in process */
krb5_keyblock *initial_key;
diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
index 232e78bc05..3394f8a58e 100644
--- a/src/plugins/preauth/spake/spake_kdc.c
+++ b/src/plugins/preauth/spake/spake_kdc.c
@@ -43,6 +43,10 @@
#include <openssl/crypto.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/fips.h>
+#endif
+
/*
* The SPAKE kdcpreauth module uses a secure cookie containing the following
* concatenated fields (all integer fields are big-endian):
--
2.41.0

@ -1,31 +0,0 @@
From f9429a9944b056376a1ff06e84dbf7e94f0d3108 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Mon, 9 Jan 2023 22:39:52 +0100
Subject: [PATCH] [downstream] Do not set root as ksu file owner
Upstream Makefile uses the install command to set root as owner of the
ksu executable file. However, this is no longer supported on latest
versions of the Mock build environment.
In case of ksu, the owner, group, and mode are already set using %attr()
in the specfile.
---
src/config/pre.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/config/pre.in b/src/config/pre.in
index 7eaa2f351c..e9ae71471e 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -185,7 +185,7 @@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ $(INSTALL_STRIP)
INSTALL_SCRIPT=@INSTALL_PROGRAM@
INSTALL_DATA=@INSTALL_DATA@
INSTALL_SHLIB=@INSTALL_SHLIB@
-INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755 -o root
+INSTALL_SETUID=$(INSTALL)
## This is needed because autoconf will sometimes define @exec_prefix@ to be
## ${prefix}.
prefix=@prefix@
--
2.41.0

@ -1,165 +0,0 @@
From c002d03cce1c82e74a0c76b323c1bf1e619d022e Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 19 Jan 2023 19:22:27 +0100
Subject: [PATCH] [downstream] Allow KRB5KDF, MD5, and MD4 in FIPS mode
OpenSSL's restrictions to use KRB5KDF, MD5, and MD4 in FIPS mode are
bypassed in case AES SHA-1 HMAC or RC4 encryption types are allowed by
the crypto policy.
---
.../crypto/openssl/hash_provider/hash_evp.c | 97 +++++++++++++++++--
src/lib/crypto/openssl/kdf.c | 2 +-
2 files changed, 89 insertions(+), 10 deletions(-)
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
index 11659908bb..eb2e693e9f 100644
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
@@ -44,6 +44,49 @@
#define EVP_MD_CTX_free EVP_MD_CTX_destroy
#endif
+#include <openssl/provider.h>
+#include <openssl/fips.h>
+#include <threads.h>
+
+typedef struct ossl_lib_md_context {
+ OSSL_LIB_CTX *libctx;
+ OSSL_PROVIDER *default_provider;
+ OSSL_PROVIDER *legacy_provider;
+} ossl_md_context_t;
+
+static thread_local ossl_md_context_t *ossl_md_ctx = NULL;
+
+static krb5_error_code
+init_ossl_md_ctx(ossl_md_context_t *ctx, const char *algo)
+{
+ ctx->libctx = OSSL_LIB_CTX_new();
+ if (!ctx->libctx)
+ return KRB5_CRYPTO_INTERNAL;
+
+ /* Load both legacy and default provider as both may be needed. */
+ ctx->default_provider = OSSL_PROVIDER_load(ctx->libctx, "default");
+ ctx->legacy_provider = OSSL_PROVIDER_load(ctx->libctx, "legacy");
+
+ if (!(ctx->default_provider && ctx->legacy_provider))
+ return KRB5_CRYPTO_INTERNAL;
+
+ return 0;
+}
+
+static void
+deinit_ossl_ctx(ossl_md_context_t *ctx)
+{
+ if (ctx->legacy_provider)
+ OSSL_PROVIDER_unload(ctx->legacy_provider);
+
+ if (ctx->default_provider)
+ OSSL_PROVIDER_unload(ctx->default_provider);
+
+ if (ctx->libctx)
+ OSSL_LIB_CTX_free(ctx->libctx);
+}
+
+
static krb5_error_code
hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
krb5_data *output)
@@ -60,11 +103,6 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
if (ctx == NULL)
return ENOMEM;
- if (type == EVP_md4() || type == EVP_md5()) {
- /* See comments below in hash_md4() and hash_md5(). */
- EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
- }
-
ok = EVP_DigestInit_ex(ctx, type, NULL);
for (i = 0; i < num_data; i++) {
if (!SIGN_IOV(&data[i]))
@@ -77,6 +115,43 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
return ok ? 0 : KRB5_CRYPTO_INTERNAL;
}
+static krb5_error_code
+hash_legacy_evp(const char *algo, const krb5_crypto_iov *data, size_t num_data,
+ krb5_data *output)
+{
+ krb5_error_code err;
+ EVP_MD *md = NULL;
+
+ if (!ossl_md_ctx) {
+ ossl_md_ctx = malloc(sizeof(ossl_md_context_t));
+ if (!ossl_md_ctx) {
+ err = ENOMEM;
+ goto end;
+ }
+
+ err = init_ossl_md_ctx(ossl_md_ctx, algo);
+ if (err) {
+ deinit_ossl_ctx(ossl_md_ctx);
+ free(ossl_md_ctx);
+ ossl_md_ctx = NULL;
+ goto end;
+ }
+ }
+
+ md = EVP_MD_fetch(ossl_md_ctx->libctx, algo, NULL);
+ if (!md) {
+ err = KRB5_CRYPTO_INTERNAL;
+ goto end;
+ }
+
+ err = hash_evp(md, data, num_data, output);
+
+end:
+ if (md)
+ EVP_MD_free(md);
+
+ return err;
+}
#endif
#ifdef K5_OPENSSL_MD4
@@ -88,7 +163,8 @@ hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
* by IPA. These keys are only used along a (separately) secured channel
* for legacy reasons when performing trusts to Active Directory.
*/
- return hash_evp(EVP_md4(), data, num_data, output);
+ return FIPS_mode() ? hash_legacy_evp("MD4", data, num_data, output)
+ : hash_evp(EVP_md4(), data, num_data, output);
}
const struct krb5_hash_provider krb5int_hash_md4 = {
@@ -100,9 +176,12 @@ const struct krb5_hash_provider krb5int_hash_md4 = {
static krb5_error_code
hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
{
- /* MD5 is needed in FIPS mode for communication with RADIUS servers. This
- * is gated in libkrad by libdefaults->radius_md5_fips_override. */
- return hash_evp(EVP_md5(), data, num_data, output);
+ /*
+ * MD5 is needed in FIPS mode for communication with RADIUS servers. This
+ * is gated in libkrad by libdefaults->radius_md5_fips_override.
+ */
+ return FIPS_mode() ? hash_legacy_evp("MD5", data, num_data, output)
+ : hash_evp(EVP_md5(), data, num_data, output);
}
const struct krb5_hash_provider krb5int_hash_md5 = {
diff --git a/src/lib/crypto/openssl/kdf.c b/src/lib/crypto/openssl/kdf.c
index 5a43c3d9eb..8528ddc4a9 100644
--- a/src/lib/crypto/openssl/kdf.c
+++ b/src/lib/crypto/openssl/kdf.c
@@ -198,7 +198,7 @@ k5_derive_random_rfc3961(const struct krb5_enc_provider *enc, krb5_key key,
goto done;
}
- kdf = EVP_KDF_fetch(NULL, "KRB5KDF", NULL);
+ kdf = EVP_KDF_fetch(NULL, "KRB5KDF", "-fips");
if (kdf == NULL) {
ret = KRB5_CRYPTO_INTERNAL;
goto done;
--
2.41.0

@ -1,279 +0,0 @@
From 83c99246ae9b157e462142daddccca5e18c2f3fd Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 15 Mar 2023 15:56:34 +0100
Subject: [PATCH] [downstream] Allow to set PAC ticket signature as optional
MS-PAC states that "The ticket signature SHOULD be included in tickets
that are not encrypted to the krbtgt account". However, the
implementation of krb5_kdc_verify_ticket() will require the ticket
signature to be present in case the target of the request is a service
principal.
In gradual upgrade environments, it results in S4U2Proxy requests
against a 1.20 KDC using a service ticket generated by an older version
KDC to fail.
This commit adds a krb5_kdc_verify_ticket_ext() function with an extra
switch parameter to tolerate the absence of ticket signature in this
scenario. If the ticket signature is present, it has to be valid,
regardless of this parameter.
This parameter is set based on the "optional_pac_tkt_chksum" string
attribute of the TGT KDB entry.
---
doc/admin/admin_commands/kadmin_local.rst | 6 ++++
doc/appdev/refs/api/index.rst | 1 +
src/include/kdb.h | 1 +
src/include/krb5/krb5.hin | 40 +++++++++++++++++++++++
src/kdc/kdc_util.c | 32 ++++++++++++++----
src/lib/krb5/krb/pac.c | 31 +++++++++++++++---
src/lib/krb5/libkrb5.exports | 1 +
src/man/kadmin.man | 6 ++++
8 files changed, 108 insertions(+), 10 deletions(-)
diff --git a/doc/admin/admin_commands/kadmin_local.rst b/doc/admin/admin_commands/kadmin_local.rst
index 2435b3c361..58ac79549f 100644
--- a/doc/admin/admin_commands/kadmin_local.rst
+++ b/doc/admin/admin_commands/kadmin_local.rst
@@ -658,6 +658,12 @@ KDC:
Directory realm when using aes-sha2 keys on the local krbtgt
entry.
+**optional_pac_tkt_chksum**
+ Boolean value defining the behavior of the KDC in case an expected
+ ticket checksum signed with one of this principal keys is not
+ present in the PAC. This is typically the case for TGS or
+ cross-realm TGS principals when processing S4U2Proxy requests.
+
This command requires the **modify** privilege.
Alias: **setstr**
diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst
index d12be47c3c..9b95ebd0f9 100644
--- a/doc/appdev/refs/api/index.rst
+++ b/doc/appdev/refs/api/index.rst
@@ -225,6 +225,7 @@ Rarely used public interfaces
krb5_is_referral_realm.rst
krb5_kdc_sign_ticket.rst
krb5_kdc_verify_ticket.rst
+ krb5_kdc_verify_ticket_ext.rst
krb5_kt_add_entry.rst
krb5_kt_end_seq_get.rst
krb5_kt_get_entry.rst
diff --git a/src/include/kdb.h b/src/include/kdb.h
index 745b24f351..6075349e5e 100644
--- a/src/include/kdb.h
+++ b/src/include/kdb.h
@@ -136,6 +136,7 @@
#define KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE "pac_privsvr_enctype"
#define KRB5_KDB_SK_SESSION_ENCTYPES "session_enctypes"
#define KRB5_KDB_SK_REQUIRE_AUTH "require_auth"
+#define KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM "optional_pac_tkt_chksum"
#if !defined(_WIN32)
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 350bcf86f2..17e1b52266 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -8356,6 +8356,46 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
const krb5_keyblock *server,
const krb5_keyblock *privsvr, krb5_pac *pac_out);
+/**
+ * Verify a PAC, possibly including ticket signature
+ *
+ * @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)
+ * @paran [in] optional_tkt_chksum Whether to require a ticket checksum
+ * @param [out] pac_out Verified PAC (NULL if no PAC included)
+ *
+ * This function is an extension of krb5_kdc_verify_ticket(), adding the @a
+ * optional_tkt_chksum parameter allowing to tolerate the absence of the PAC
+ * ticket signature.
+ *
+ * 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 and
+ * @a optional_tkt_chksum is FALSE, 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.
+ *
+ * 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
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_kdc_verify_ticket_ext(krb5_context context,
+ const krb5_enc_tkt_part *enc_tkt,
+ krb5_const_principal server_princ,
+ const krb5_keyblock *server,
+ const krb5_keyblock *privsvr,
+ krb5_boolean optional_tkt_chksum,
+ 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,
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index fe4e48209a..93415ba862 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -560,16 +560,36 @@ cleanup:
static krb5_error_code
try_verify_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
krb5_db_entry *server, krb5_keyblock *server_key,
- const krb5_keyblock *tgt_key, krb5_pac *pac_out)
+ krb5_db_entry *tgt, const krb5_keyblock *tgt_key,
+ krb5_pac *pac_out)
{
krb5_error_code ret;
+ krb5_boolean optional_tkt_chksum;
+ char *str = NULL;
krb5_keyblock *privsvr_key;
ret = pac_privsvr_key(context, server, tgt_key, &privsvr_key);
if (ret)
return ret;
- ret = krb5_kdc_verify_ticket(context, enc_tkt, server->princ, server_key,
- privsvr_key, pac_out);
+
+ /* Check if the absence of ticket signature is tolerated for this realm */
+ ret = krb5_dbe_get_string(context, tgt,
+ KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM, &str);
+ /* TODO: should be using _krb5_conf_boolean(), but os-proto.h is not
+ * available here.
+ */
+ optional_tkt_chksum = !ret && str && (strncasecmp(str, "true", 4) == 0
+ || strncasecmp(str, "t", 1) == 0
+ || strncasecmp(str, "yes", 3) == 0
+ || strncasecmp(str, "y", 1) == 0
+ || strncasecmp(str, "1", 1) == 0
+ || strncasecmp(str, "on", 2) == 0);
+
+ krb5_dbe_free_string(context, str);
+
+ ret = krb5_kdc_verify_ticket_ext(context, enc_tkt, server->princ,
+ server_key, privsvr_key,
+ optional_tkt_chksum, pac_out);
krb5_free_keyblock(context, privsvr_key);
return ret;
}
@@ -599,7 +619,7 @@ get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
server_key, NULL, pac_out);
}
- ret = try_verify_pac(context, enc_tkt, server, server_key, tgt_key,
+ ret = try_verify_pac(context, enc_tkt, server, server_key, tgt, tgt_key,
pac_out);
if (ret != KRB5KRB_AP_ERR_MODIFIED && ret != KRB5_BAD_ENCTYPE)
return ret;
@@ -613,8 +633,8 @@ get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &old_key, NULL);
if (ret)
return ret;
- ret = try_verify_pac(context, enc_tkt, server, server_key, &old_key,
- pac_out);
+ ret = try_verify_pac(context, enc_tkt, server, server_key, tgt,
+ &old_key, pac_out);
krb5_free_keyblock_contents(context, &old_key);
if (!ret)
return 0;
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
index 5d1fdf1ba0..0c0e2ada68 100644
--- a/src/lib/krb5/krb/pac.c
+++ b/src/lib/krb5/krb/pac.c
@@ -594,6 +594,19 @@ 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)
+{
+ return krb5_kdc_verify_ticket_ext(context, enc_tkt, server_princ, server,
+ privsvr, FALSE, pac_out);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_kdc_verify_ticket_ext(krb5_context context,
+ const krb5_enc_tkt_part *enc_tkt,
+ krb5_const_principal server_princ,
+ const krb5_keyblock *server,
+ const krb5_keyblock *privsvr,
+ krb5_boolean optional_tkt_chksum,
+ krb5_pac *pac_out)
{
krb5_error_code ret;
krb5_pac pac = NULL;
@@ -602,7 +615,7 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
krb5_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;
+ krb5_boolean is_service_tkt, has_tkt_chksum = FALSE;
size_t i, j;
*pac_out = NULL;
@@ -667,11 +680,21 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
ret = verify_checksum(context, pac, KRB5_PAC_TICKET_CHECKSUM, privsvr,
KRB5_KEYUSAGE_APP_DATA_CKSUM, recoded_tkt);
- if (ret)
- goto cleanup;
+ if (ret) {
+ if (!optional_tkt_chksum)
+ goto cleanup;
+ else if (ret != ENOENT)
+ goto cleanup;
+ /* Otherwise ticket signature is absent but optional. Proceed... */
+ } else {
+ has_tkt_chksum = TRUE;
+ }
}
+ /* Else, we make the assumption the ticket signature is absent in case this
+ * is not a service ticket.
+ */
- ret = verify_pac_checksums(context, pac, is_service_tkt, server, privsvr);
+ ret = verify_pac_checksums(context, pac, has_tkt_chksum, server, privsvr);
if (ret)
goto cleanup;
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 4c50e935a2..d4b0455c8c 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -463,6 +463,7 @@ krb5_is_thread_safe
krb5_kdc_rep_decrypt_proc
krb5_kdc_sign_ticket
krb5_kdc_verify_ticket
+krb5_kdc_verify_ticket_ext
krb5_kt_add_entry
krb5_kt_client_default
krb5_kt_close
diff --git a/src/man/kadmin.man b/src/man/kadmin.man
index c29638a227..1da1609cc8 100644
--- a/src/man/kadmin.man
+++ b/src/man/kadmin.man
@@ -724,6 +724,12 @@ encryption type. It may be necessary to set this value to
"aes256\-sha1" on the cross\-realm krbtgt entry for an Active
Directory realm when using aes\-sha2 keys on the local krbtgt
entry.
+.TP
+\fBoptional_pac_tkt_chksum\fP
+Boolean value defining the behavior of the KDC in case an expected ticket
+checksum signed with one of this principal keys is not present in the PAC. This
+is typically the case for TGS or cross-realm TGS principals when processing
+S4U2Proxy requests.
.UNINDENT
.sp
This command requires the \fBmodify\fP privilege.
--
2.41.0

@ -1,47 +0,0 @@
From fef5896463a50e94d3a68f59f7c78a6e943ac5ad Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Tue, 23 May 2023 12:19:54 +0200
Subject: [PATCH] [downstream] Make PKINIT CMS SHA-1 signature verification
available in FIPS mode
We recommend using the SHA1 crypto-module in order to allow the
verification of SHA-1 signature for CMS messages. However, this module
does not work in FIPS mode, because the SHA-1 algorithm is absent from
the OpenSSL FIPS provider.
This commit enables the signature verification process to fetch the
algorithm from a non-FIPS OpenSSL provider.
Support for SHA-1 CMS signature is still required, especially in order
to interoperate with Active Directory. At least it is until elliptic
curve cryptography is implemented for PKINIT in MIT krb5.
---
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index f41328763e..263ef7845e 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -1844,8 +1844,17 @@ cms_signeddata_verify(krb5_context context,
if (oid == NULL)
goto cleanup;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ /* Do not use FIPS provider (even in FIPS mode) because it keeps from
+ * allowing SHA-1 signature verification using the SHA1 crypto-module
+ */
+ cms = CMS_ContentInfo_new_ex(NULL, "-fips");
+ if (!cms)
+ goto cleanup;
+#endif
+
/* decode received CMS message */
- if ((cms = d2i_CMS_ContentInfo(NULL, &p, (int)signed_data_len)) == NULL) {
+ if (!d2i_CMS_ContentInfo(&cms, &p, (int)signed_data_len)) {
retval = oerr(context, 0, _("Failed to decode CMS message"));
goto cleanup;
}
--
2.41.0

@ -1,217 +0,0 @@
From 906d3441b846ed09882490b6128db6fedf39e63b Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 30 May 2023 01:21:48 -0400
Subject: [PATCH] Enable PKINIT if at least one group is available
OpenSSL may no longer allow decoding of non-well-known Diffie-Hellman
group parameters as EVP_PKEY objects in FIPS mode. However, OpenSSL
does not know about MODP group 2 (1024-bit), which is considered as a
custom group. As a consequence, the PKINIT kdcpreauth module fails to
load in FIPS mode.
Allow initialization of PKINIT plugin if at least one of the MODP
well-known group parameters successfully decodes.
[ghudson@mit.edu: minor commit message and code edits]
ticket: 9096 (new)
---
src/plugins/preauth/pkinit/pkinit_clnt.c | 2 +-
src/plugins/preauth/pkinit/pkinit_crypto.h | 3 +-
.../preauth/pkinit/pkinit_crypto_openssl.c | 76 +++++++++++--------
src/plugins/preauth/pkinit/pkinit_srv.c | 2 +-
src/plugins/preauth/pkinit/pkinit_trace.h | 3 +
5 files changed, 51 insertions(+), 35 deletions(-)
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index 725d5bc438..ea9ba454df 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -1378,7 +1378,7 @@ pkinit_client_plugin_init(krb5_context context,
if (retval)
goto errout;
- retval = pkinit_init_plg_crypto(&ctx->cryptoctx);
+ retval = pkinit_init_plg_crypto(context, &ctx->cryptoctx);
if (retval)
goto errout;
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 9fa315d7a0..8bdbea8e95 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -103,7 +103,8 @@ typedef struct _pkinit_cert_matching_data {
/*
* Functions to initialize and cleanup crypto contexts
*/
-krb5_error_code pkinit_init_plg_crypto(pkinit_plg_crypto_context *);
+krb5_error_code pkinit_init_plg_crypto(krb5_context,
+ pkinit_plg_crypto_context *);
void pkinit_fini_plg_crypto(pkinit_plg_crypto_context);
krb5_error_code pkinit_init_req_crypto(pkinit_req_crypto_context *);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 263ef7845e..d646073d55 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -47,7 +47,8 @@
static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context );
static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context );
-static krb5_error_code pkinit_init_dh_params(pkinit_plg_crypto_context );
+static krb5_error_code pkinit_init_dh_params(krb5_context,
+ pkinit_plg_crypto_context);
static void pkinit_fini_dh_params(pkinit_plg_crypto_context );
static krb5_error_code pkinit_init_certs(pkinit_identity_crypto_context ctx);
@@ -951,7 +952,8 @@ oerr_cert(krb5_context context, krb5_error_code code, X509_STORE_CTX *certctx,
}
krb5_error_code
-pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx)
+pkinit_init_plg_crypto(krb5_context context,
+ pkinit_plg_crypto_context *cryptoctx)
{
krb5_error_code retval = ENOMEM;
pkinit_plg_crypto_context ctx = NULL;
@@ -969,7 +971,7 @@ pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx)
if (retval)
goto out;
- retval = pkinit_init_dh_params(ctx);
+ retval = pkinit_init_dh_params(context, ctx);
if (retval)
goto out;
@@ -1278,30 +1280,36 @@ pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
ASN1_OBJECT_free(ctx->id_kp_serverAuth);
}
-static krb5_error_code
-pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
+static int
+try_import_group(krb5_context context, const krb5_data *params,
+ const char *name, EVP_PKEY **pkey_out)
{
- krb5_error_code retval = ENOMEM;
-
- plgctx->dh_1024 = decode_dh_params(&oakley_1024);
- if (plgctx->dh_1024 == NULL)
- goto cleanup;
-
- plgctx->dh_2048 = decode_dh_params(&oakley_2048);
- if (plgctx->dh_2048 == NULL)
- goto cleanup;
+ *pkey_out = decode_dh_params(params);
+ if (*pkey_out == NULL)
+ TRACE_PKINIT_DH_GROUP_UNAVAILABLE(context, name);
+ return (*pkey_out != NULL) ? 1 : 0;
+}
- plgctx->dh_4096 = decode_dh_params(&oakley_4096);
- if (plgctx->dh_4096 == NULL)
- goto cleanup;
+static krb5_error_code
+pkinit_init_dh_params(krb5_context context, pkinit_plg_crypto_context plgctx)
+{
+ int n = 0;
- retval = 0;
+ n += try_import_group(context, &oakley_1024, "MODP 2 (1024-bit)",
+ &plgctx->dh_1024);
+ n += try_import_group(context, &oakley_2048, "MODP 14 (2048-bit)",
+ &plgctx->dh_2048);
+ n += try_import_group(context, &oakley_4096, "MODP 16 (4096-bit)",
+ &plgctx->dh_4096);
-cleanup:
- if (retval)
+ if (n == 0) {
pkinit_fini_dh_params(plgctx);
+ k5_setmsg(context, ENOMEM,
+ _("PKINIT cannot initialize any key exchange groups"));
+ return ENOMEM;
+ }
- return retval;
+ return 0;
}
static void
@@ -2910,11 +2918,11 @@ client_create_dh(krb5_context context,
if (cryptoctx->received_params != NULL)
params = cryptoctx->received_params;
- else if (dh_size == 1024)
+ else if (plg_cryptoctx->dh_1024 != NULL && dh_size == 1024)
params = plg_cryptoctx->dh_1024;
- else if (dh_size == 2048)
+ else if (plg_cryptoctx->dh_2048 != NULL && dh_size == 2048)
params = plg_cryptoctx->dh_2048;
- else if (dh_size == 4096)
+ else if (plg_cryptoctx->dh_4096 != NULL && dh_size == 4096)
params = plg_cryptoctx->dh_4096;
else
goto cleanup;
@@ -3210,19 +3218,23 @@ pkinit_create_td_dh_parameters(krb5_context context,
krb5_algorithm_identifier alg_4096 = { dh_oid, oakley_4096 };
krb5_algorithm_identifier *alglist[4];
- if (opts->dh_min_bits > 4096) {
- ret = KRB5KRB_ERR_GENERIC;
- goto cleanup;
- }
-
i = 0;
- if (opts->dh_min_bits <= 2048)
+ if (plg_cryptoctx->dh_2048 != NULL && opts->dh_min_bits <= 2048)
alglist[i++] = &alg_2048;
- alglist[i++] = &alg_4096;
- if (opts->dh_min_bits <= 1024)
+ if (plg_cryptoctx->dh_4096 != NULL && opts->dh_min_bits <= 4096)
+ alglist[i++] = &alg_4096;
+ if (plg_cryptoctx->dh_1024 != NULL && opts->dh_min_bits <= 1024)
alglist[i++] = &alg_1024;
alglist[i] = NULL;
+ if (i == 0) {
+ ret = KRB5KRB_ERR_GENERIC;
+ k5_setmsg(context, ret,
+ _("OpenSSL has no supported key exchange groups for "
+ "pkinit_dh_min_bits=%d"), opts->dh_min_bits);
+ goto cleanup;
+ }
+
ret = k5int_encode_krb5_td_dh_parameters(alglist, &der_alglist);
if (ret)
goto cleanup;
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index 1b3bf6d4d0..768a4e559f 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -1222,7 +1222,7 @@ pkinit_server_plugin_init_realm(krb5_context context, const char *realmname,
goto errout;
plgctx->realmname_len = strlen(plgctx->realmname);
- retval = pkinit_init_plg_crypto(&plgctx->cryptoctx);
+ retval = pkinit_init_plg_crypto(context, &plgctx->cryptoctx);
if (retval)
goto errout;
diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
index 259e95c6c2..5ee39c085c 100644
--- a/src/plugins/preauth/pkinit/pkinit_trace.h
+++ b/src/plugins/preauth/pkinit/pkinit_trace.h
@@ -90,6 +90,9 @@
#define TRACE_PKINIT_CLIENT_TRYAGAIN(c) \
TRACE(c, "PKINIT client trying again with KDC-provided parameters")
+#define TRACE_PKINIT_DH_GROUP_UNAVAILABLE(c, name) \
+ TRACE(c, "PKINIT key exchange group {str} unsupported", name)
+
#define TRACE_PKINIT_OPENSSL_ERROR(c, msg) \
TRACE(c, "PKINIT OpenSSL error: {str}", msg)
--
2.41.0

@ -1,48 +0,0 @@
From 137e424f7ae7c054e1dcb41c929a961bb021ed8b Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@samba.org>
Date: Fri, 4 Aug 2023 09:54:06 +0200
Subject: [PATCH] Fix double-free in KDC TGS processing
When issuing a ticket for a TGS renew or validate request, copy only
the server field from the outer part of the header ticket to the new
ticket. Copying the whole structure causes the enc_part pointer to be
aliased to the header ticket until krb5_encrypt_tkt_part() is called,
resulting in a double-free if handle_authdata() fails.
[ghudson@mit.edu: changed the fix to avoid aliasing enc_part rather
than check for aliasing before freeing; rewrote commit message]
CVE-2023-39975:
In MIT krb5 release 1.21, an authenticated attacker can cause a KDC to
free the same pointer twice if it can induce a failure in
authorization data handling.
ticket: 9101 (new)
tags: pullup
target_version: 1.21-next
(cherry picked from commit 88a1701b423c13991a8064feeb26952d3641d840)
---
src/kdc/do_tgs_req.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 6e4c8fa9f3..0acc45850f 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -1010,8 +1010,9 @@ tgs_issue_ticket(kdc_realm_t *realm, struct tgs_req_info *t,
}
if (t->req->kdc_options & (KDC_OPT_VALIDATE | KDC_OPT_RENEW)) {
- /* Copy the whole header ticket except for authorization data. */
- ticket_reply = *t->header_tkt;
+ /* Copy the header ticket server and all enc-part fields except for
+ * authorization data. */
+ ticket_reply.server = t->header_tkt->server;
enc_tkt_reply = *t->header_tkt->enc_part2;
enc_tkt_reply.authorization_data = NULL;
} else {
--
2.41.0

File diff suppressed because it is too large Load Diff

@ -1,381 +0,0 @@
From 0cb2e6c09fee3863c16664bf180e773f662cd313 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Steffen=20Kie=C3=9F?=
<steffen.kiess@cis.iti.uni-stuttgart.de>
Date: Tue, 13 Feb 2024 18:39:27 +0100
Subject: [PATCH] Avoid strict-prototype compiler errors
Commit 4b9d7f7c107f01a61600fddcd8cde3812d0366a2 added the
-Werror=strict-prototypes parameter to the build process, but left
behind 28 function definitions using "()" instead of "(void)". Most
of these definitions could not cause compiler errors for various
reasons (such as an accompanying prototype), but a few could cause
errors in gcc depending on the build configuration.
For consistency and safety, add "(void)" to all 28 definitions.
[ghudson@mit.edu: rewrote commit message]
(cherry picked from commit 3ae9244cd021a75eba909d872a92c25db490714d)
---
src/clients/kcpytkt/kcpytkt.c | 2 +-
src/clients/kdeltkt/kdeltkt.c | 2 +-
src/clients/kinit/kinit.c | 4 ++--
src/clients/kinit/kinit_kdb.c | 2 +-
src/clients/klist/klist.c | 4 ++--
src/kadmin/cli/kadmin.c | 2 +-
src/kadmin/dbutil/kdb5_util.c | 4 ++--
src/kdc/main.c | 2 +-
src/kprop/kpropd.c | 4 ++--
src/lib/crypto/builtin/enc_provider/aes.c | 2 +-
src/lib/crypto/openssl/hmac.c | 2 +-
src/lib/krb5/ccache/t_memory.c | 4 ++--
src/lib/krb5/ccache/t_stdio.c | 4 ++--
src/plugins/kdb/db2/libdb2/btree/bt_debug.c | 2 +-
src/plugins/kdb/db2/libdb2/btree/bt_open.c | 4 ++--
src/plugins/kdb/db2/libdb2/hash/dbm.c | 2 +-
src/plugins/kdb/db2/libdb2/test/btree.tests/main.c | 2 +-
src/plugins/kdb/db2/libdb2/test/dbtest.c | 2 +-
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 2 +-
src/plugins/tls/k5tls/openssl.c | 2 +-
src/tests/asn.1/make-vectors.c | 2 +-
21 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/src/clients/kcpytkt/kcpytkt.c b/src/clients/kcpytkt/kcpytkt.c
index 0b8802261e..f1d50e5de0 100644
--- a/src/clients/kcpytkt/kcpytkt.c
+++ b/src/clients/kcpytkt/kcpytkt.c
@@ -10,7 +10,7 @@ static char *prog;
static int quiet = 0;
static void
-xusage()
+xusage(void)
{
fprintf(stderr, "xusage: %s [-c from_ccache] [-e etype] [-f flags] "
"dest_ccache service1 service2 ...\n", prog);
diff --git a/src/clients/kdeltkt/kdeltkt.c b/src/clients/kdeltkt/kdeltkt.c
index cd0bf637db..66a32a8bd3 100644
--- a/src/clients/kdeltkt/kdeltkt.c
+++ b/src/clients/kdeltkt/kdeltkt.c
@@ -10,7 +10,7 @@ static char *prog;
static int quiet = 0;
static void
-xusage()
+xusage(void)
{
fprintf(stderr, "xusage: %s [-c ccache] [-e etype] [-f flags] service1 "
"service2 ...\n", prog);
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
index 7a33ffae59..b27b723f2d 100644
--- a/src/clients/kinit/kinit.c
+++ b/src/clients/kinit/kinit.c
@@ -55,7 +55,7 @@ get_name_from_os(void)
#else /* HAVE_PWD_H */
#ifdef _WIN32
static char *
-get_name_from_os()
+get_name_from_os(void)
{
static char name[1024];
DWORD name_size = sizeof(name);
@@ -69,7 +69,7 @@ get_name_from_os()
}
#else /* _WIN32 */
static char *
-get_name_from_os()
+get_name_from_os(void)
{
return NULL;
}
diff --git a/src/clients/kinit/kinit_kdb.c b/src/clients/kinit/kinit_kdb.c
index fbd174bf0c..4e7cd50169 100644
--- a/src/clients/kinit/kinit_kdb.c
+++ b/src/clients/kinit/kinit_kdb.c
@@ -69,7 +69,7 @@ kinit_kdb_init(krb5_context *pcontext, char *realm)
}
void
-kinit_kdb_fini()
+kinit_kdb_fini(void)
{
kadm5_destroy(server_handle);
}
diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c
index c797b1698f..27cf0ee11b 100644
--- a/src/clients/klist/klist.c
+++ b/src/clients/klist/klist.c
@@ -359,7 +359,7 @@ do_keytab(const char *name)
}
static void
-list_all_ccaches()
+list_all_ccaches(void)
{
krb5_error_code ret;
krb5_ccache cache;
@@ -451,7 +451,7 @@ show_all_ccaches(void)
}
static void
-do_ccache()
+do_ccache(void)
{
krb5_error_code ret;
krb5_ccache cache;
diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c
index 23b64b0f58..c1256f7708 100644
--- a/src/kadmin/cli/kadmin.c
+++ b/src/kadmin/cli/kadmin.c
@@ -607,7 +607,7 @@ kadmin_startup(int argc, char *argv[], char **request_out, char ***args_out)
}
int
-quit()
+quit(void)
{
kadm5_ret_t retval;
diff --git a/src/kadmin/dbutil/kdb5_util.c b/src/kadmin/dbutil/kdb5_util.c
index 55d529fa4c..b9b61e3f91 100644
--- a/src/kadmin/dbutil/kdb5_util.c
+++ b/src/kadmin/dbutil/kdb5_util.c
@@ -367,7 +367,7 @@ main(int argc, char *argv[])
* program is run).
*/
static int
-open_db_and_mkey()
+open_db_and_mkey(void)
{
krb5_error_code retval;
krb5_data scratch, pwd, seed;
@@ -489,7 +489,7 @@ open_db_and_mkey()
#endif
int
-quit()
+quit(void)
{
krb5_error_code retval;
static krb5_boolean finished = 0;
diff --git a/src/kdc/main.c b/src/kdc/main.c
index b43fe9a082..2dfad5673f 100644
--- a/src/kdc/main.c
+++ b/src/kdc/main.c
@@ -854,7 +854,7 @@ write_pid_file(const char *path)
}
static void
-finish_realms()
+finish_realms(void)
{
int i;
diff --git a/src/kprop/kpropd.c b/src/kprop/kpropd.c
index f883ae2df8..fbb8e37ae9 100644
--- a/src/kprop/kpropd.c
+++ b/src/kprop/kpropd.c
@@ -376,7 +376,7 @@ get_wildcard_addr(struct addrinfo **res)
}
static void
-do_standalone()
+do_standalone(void)
{
struct sockaddr_in frominet;
struct addrinfo *res;
@@ -639,7 +639,7 @@ full_resync(CLIENT *clnt)
* Returns non-zero on failure due to errors.
*/
krb5_error_code
-do_iprop()
+do_iprop(void)
{
kadm5_ret_t retval;
krb5_principal iprop_svc_principal = NULL;
diff --git a/src/lib/crypto/builtin/enc_provider/aes.c b/src/lib/crypto/builtin/enc_provider/aes.c
index 7fa9449797..39e2a84005 100644
--- a/src/lib/crypto/builtin/enc_provider/aes.c
+++ b/src/lib/crypto/builtin/enc_provider/aes.c
@@ -69,7 +69,7 @@ void k5_iEnc256_CBC(struct aes_data *data);
void k5_iDec256_CBC(struct aes_data *data);
static krb5_boolean
-aesni_supported_by_cpu()
+aesni_supported_by_cpu(void)
{
unsigned int a, b, c, d;
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
index 25a419d73a..32dec3022e 100644
--- a/src/lib/crypto/openssl/hmac.c
+++ b/src/lib/crypto/openssl/hmac.c
@@ -71,7 +71,7 @@
#define HMAC_CTX_new compat_hmac_ctx_new
static HMAC_CTX *
-compat_hmac_ctx_new()
+compat_hmac_ctx_new(void)
{
HMAC_CTX *ctx;
diff --git a/src/lib/krb5/ccache/t_memory.c b/src/lib/krb5/ccache/t_memory.c
index 6d103a00d1..0f94e823cb 100644
--- a/src/lib/krb5/ccache/t_memory.c
+++ b/src/lib/krb5/ccache/t_memory.c
@@ -85,7 +85,7 @@ krb5_creds test_creds = {
};
void
-init_test_cred()
+init_test_cred(void)
{
test_creds.client = (krb5_principal) malloc(sizeof(krb5_data *)*3);
test_creds.client[0] = &client1;
@@ -104,7 +104,7 @@ init_test_cred()
};
void
-mcc_test()
+mcc_test(void)
{
krb5_ccache id;
krb5_creds creds;
diff --git a/src/lib/krb5/ccache/t_stdio.c b/src/lib/krb5/ccache/t_stdio.c
index 15185e301c..06a9c2dea1 100644
--- a/src/lib/krb5/ccache/t_stdio.c
+++ b/src/lib/krb5/ccache/t_stdio.c
@@ -98,7 +98,7 @@ krb5_creds test_creds = {
};
void
-init_test_cred()
+init_test_cred(void)
{
test_creds.client = (krb5_principal) malloc(sizeof(krb5_data *)*3);
test_creds.client[0] = &client1;
@@ -118,7 +118,7 @@ init_test_cred()
int flags = 0;
void
-scc_test()
+scc_test(void)
{
krb5_ccache id;
krb5_creds creds;
diff --git a/src/plugins/kdb/db2/libdb2/btree/bt_debug.c b/src/plugins/kdb/db2/libdb2/btree/bt_debug.c
index bc71076a35..5a955e09be 100644
--- a/src/plugins/kdb/db2/libdb2/btree/bt_debug.c
+++ b/src/plugins/kdb/db2/libdb2/btree/bt_debug.c
@@ -56,7 +56,7 @@ static FILE *tracefp;
* initialize debugging.
*/
static void
-__bt_dinit()
+__bt_dinit(void)
{
static int first = 1;
diff --git a/src/plugins/kdb/db2/libdb2/btree/bt_open.c b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
index a2910422eb..ef7515c3d4 100644
--- a/src/plugins/kdb/db2/libdb2/btree/bt_open.c
+++ b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
@@ -391,7 +391,7 @@ nroot(BTREE *t)
}
static int
-tmp()
+tmp(void)
{
#ifdef SIG_BLOCK
sigset_t set, oset;
@@ -438,7 +438,7 @@ tmp()
}
static int
-byteorder()
+byteorder(void)
{
u_int32_t x;
u_char *p;
diff --git a/src/plugins/kdb/db2/libdb2/hash/dbm.c b/src/plugins/kdb/db2/libdb2/hash/dbm.c
index 2dca256dc3..e643634433 100644
--- a/src/plugins/kdb/db2/libdb2/hash/dbm.c
+++ b/src/plugins/kdb/db2/libdb2/hash/dbm.c
@@ -143,7 +143,7 @@ kdb2_store(datum key, datum dat)
}
static void
-no_open_db()
+no_open_db(void)
{
(void)fprintf(stderr, "dbm: no open database.\n");
}
diff --git a/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c b/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c
index 088f903231..eec843d4db 100644
--- a/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c
+++ b/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c
@@ -908,7 +908,7 @@ keydata(key, data)
}
void
-usage()
+usage(void)
{
(void)fprintf(stderr,
"usage: %s [-bdluw] [-c cache] [-i file] [-p page] [file]\n",
diff --git a/src/plugins/kdb/db2/libdb2/test/dbtest.c b/src/plugins/kdb/db2/libdb2/test/dbtest.c
index 04bf34b90d..a2866b4412 100644
--- a/src/plugins/kdb/db2/libdb2/test/dbtest.c
+++ b/src/plugins/kdb/db2/libdb2/test/dbtest.c
@@ -792,7 +792,7 @@ xmalloc(char *text, size_t len)
}
void
-usage()
+usage(void)
{
(void)fprintf(stderr,
"usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 6d96499d77..af3fa9ee8b 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -3090,7 +3090,7 @@ cleanup:
}
int
-pkinit_openssl_init()
+pkinit_openssl_init(void)
{
/* Initialize OpenSSL. */
ERR_load_crypto_strings();
diff --git a/src/plugins/tls/k5tls/openssl.c b/src/plugins/tls/k5tls/openssl.c
index 99fda7ffcd..aab67c01cb 100644
--- a/src/plugins/tls/k5tls/openssl.c
+++ b/src/plugins/tls/k5tls/openssl.c
@@ -49,7 +49,7 @@ static int ex_handle_id = -1;
MAKE_INIT_FUNCTION(init_openssl);
int
-init_openssl()
+init_openssl(void)
{
SSL_library_init();
SSL_load_error_strings();
diff --git a/src/tests/asn.1/make-vectors.c b/src/tests/asn.1/make-vectors.c
index 2fc85466bb..6f2b7dd021 100644
--- a/src/tests/asn.1/make-vectors.c
+++ b/src/tests/asn.1/make-vectors.c
@@ -224,7 +224,7 @@ printbuf(void)
}
int
-main()
+main(void)
{
/* Initialize values which can't use static initializers. */
asn_long2INTEGER(&otp_format, 2); /* Alphanumeric */
--
2.44.0

@ -1,42 +0,0 @@
From f54763bc90df9c76c69ee9a837cf856bcf93e633 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 5 Mar 2024 17:38:49 -0500
Subject: [PATCH] Fix leak in KDC NDR encoding
If the KDC tries to encode a principal containing encode invalid UTF-8
sequences for inclusion in a PAC delegation info buffer, it will leak
a small amount of memory in enc_wchar_pointer() before failing. Fix
the leak.
ticket: 9115 (new)
tags: pullup
target_version: 1.21-next
(cherry picked from commit 7d0d85bf99caf60c0afd4dcf91b0c4c683b983fe)
---
src/kdc/ndr.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/kdc/ndr.c b/src/kdc/ndr.c
index 48395abe52..d438408ee2 100644
--- a/src/kdc/ndr.c
+++ b/src/kdc/ndr.c
@@ -96,14 +96,13 @@ enc_wchar_pointer(const char *utf8, struct encoded_wchars *encoded_out)
size_t utf16len, num_wchars;
uint8_t *utf16;
- k5_buf_init_dynamic(&b);
-
ret = k5_utf8_to_utf16le(utf8, &utf16, &utf16len);
if (ret)
return ret;
num_wchars = utf16len / 2;
+ k5_buf_init_dynamic(&b);
k5_buf_add_uint32_le(&b, num_wchars + 1);
k5_buf_add_uint32_le(&b, 0);
k5_buf_add_uint32_le(&b, num_wchars);
--
2.44.0

@ -1,175 +0,0 @@
From 5464ad5b64f7ce7c3d78082352189af7c8feb95f Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Fri, 6 Sep 2024 17:18:11 +0200
Subject: [PATCH] Fix various issues detected by static analysis
(cherry picked from commit 53d352949941ee236461658d01f03c37abafc6f6)
---
src/clients/klist/klist.c | 13 +++++++------
src/kadmin/dbutil/dump.c | 5 +++++
src/kdc/ndr.c | 2 +-
src/lib/kdb/decrypt_key.c | 2 +-
src/lib/rpc/svc_auth_gss.c | 5 ++++-
src/lib/rpc/svc_udp.c | 13 +++++++------
src/util/support/threads.c | 2 --
7 files changed, 25 insertions(+), 17 deletions(-)
diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c
index 27cf0ee11b..9db66f6072 100644
--- a/src/clients/klist/klist.c
+++ b/src/clients/klist/klist.c
@@ -666,7 +666,7 @@ show_credential(krb5_creds *cred)
krb5_error_code ret;
krb5_ticket *tkt = NULL;
char *name = NULL, *sname = NULL, *tktsname, *flags;
- int extra_field = 0, ccol = 0, i;
+ int extra_field = 0, ccol = 0, i, r;
krb5_boolean is_config = krb5_is_config_principal(context, cred->server);
ret = krb5_unparse_name(context, cred->client, &name);
@@ -696,11 +696,12 @@ show_credential(krb5_creds *cred)
fputs("config: ", stdout);
ccol = 8;
for (i = 1; i < cred->server->length; i++) {
- ccol += printf("%s%.*s%s",
- i > 1 ? "(" : "",
- (int)cred->server->data[i].length,
- cred->server->data[i].data,
- i > 1 ? ")" : "");
+ r = printf("%s%.*s%s", i > 1 ? "(" : "",
+ (int)cred->server->data[i].length,
+ cred->server->data[i].data,
+ i > 1 ? ")" : "");
+ if (r >= 0)
+ ccol += r;
}
fputs(" = ", stdout);
ccol += 3;
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
index 4d6cc0bdf9..feb053d834 100644
--- a/src/kadmin/dbutil/dump.c
+++ b/src/kadmin/dbutil/dump.c
@@ -704,6 +704,11 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep,
dbentry->len = u1;
dbentry->n_key_data = u4;
+
+ if (u5 > UINT16_MAX) {
+ load_err(fname, *linenop, _("invalid principal extra data size"));
+ goto fail;
+ }
dbentry->e_length = u5;
if (kp != NULL) {
diff --git a/src/kdc/ndr.c b/src/kdc/ndr.c
index d438408ee2..38be9fe42a 100644
--- a/src/kdc/ndr.c
+++ b/src/kdc/ndr.c
@@ -242,7 +242,7 @@ ndr_enc_delegation_info(struct pac_s4u_delegation_info *in, krb5_data *out)
{
krb5_error_code ret;
size_t i;
- struct k5buf b;
+ struct k5buf b = EMPTY_K5BUF;
struct encoded_wchars pt_encoded = { 0 }, *tss_encoded = NULL;
uint32_t pointer = 0;
diff --git a/src/lib/kdb/decrypt_key.c b/src/lib/kdb/decrypt_key.c
index 82bbed6312..c971793c9d 100644
--- a/src/lib/kdb/decrypt_key.c
+++ b/src/lib/kdb/decrypt_key.c
@@ -60,7 +60,7 @@ krb5_dbe_def_decrypt_key_data(krb5_context context, const krb5_keyblock *mkey,
krb5_keyblock *dbkey_out,
krb5_keysalt *keysalt_out)
{
- krb5_error_code ret;
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
int16_t keylen;
krb5_enc_data cipher;
krb5_data plain = empty_data();
diff --git a/src/lib/rpc/svc_auth_gss.c b/src/lib/rpc/svc_auth_gss.c
index 98d601c8ab..461e5de542 100644
--- a/src/lib/rpc/svc_auth_gss.c
+++ b/src/lib/rpc/svc_auth_gss.c
@@ -297,7 +297,7 @@ svcauth_gss_validate(struct svc_req *rqst, struct svc_rpc_gss_data *gd, struct r
struct opaque_auth *oa;
gss_buffer_desc rpcbuf, checksum;
OM_uint32 maj_stat, min_stat, qop_state;
- u_char rpchdr[128];
+ u_char rpchdr[32 + MAX_AUTH_BYTES];
int32_t *buf;
log_debug("in svcauth_gss_validate()");
@@ -315,6 +315,8 @@ svcauth_gss_validate(struct svc_req *rqst, struct svc_rpc_gss_data *gd, struct r
return (FALSE);
buf = (int32_t *)(void *)rpchdr;
+
+ /* Write the 32 first bytes of the header. */
IXDR_PUT_LONG(buf, msg->rm_xid);
IXDR_PUT_ENUM(buf, msg->rm_direction);
IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers);
@@ -323,6 +325,7 @@ svcauth_gss_validate(struct svc_req *rqst, struct svc_rpc_gss_data *gd, struct r
IXDR_PUT_LONG(buf, msg->rm_call.cb_proc);
IXDR_PUT_ENUM(buf, oa->oa_flavor);
IXDR_PUT_LONG(buf, oa->oa_length);
+
if (oa->oa_length) {
memcpy((caddr_t)buf, oa->oa_base, oa->oa_length);
buf += RNDUP(oa->oa_length) / sizeof(int32_t);
diff --git a/src/lib/rpc/svc_udp.c b/src/lib/rpc/svc_udp.c
index 8ecbdf2b33..3aff277eb7 100644
--- a/src/lib/rpc/svc_udp.c
+++ b/src/lib/rpc/svc_udp.c
@@ -248,8 +248,9 @@ static bool_t svcudp_reply(
{
struct svcudp_data *su = su_data(xprt);
XDR *xdrs = &su->su_xdrs;
- int slen;
+ u_int slen;
bool_t stat = FALSE;
+ ssize_t r;
xdrproc_t xdr_results = NULL;
caddr_t xdr_location = 0;
@@ -272,12 +273,12 @@ static bool_t svcudp_reply(
if (xdr_replymsg(xdrs, msg) &&
(!has_args ||
(SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) {
- slen = (int)XDR_GETPOS(xdrs);
- if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0,
- (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen)
- == slen) {
+ slen = XDR_GETPOS(xdrs);
+ r = sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0,
+ (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen);
+ if (r >= 0 && (u_int)r == slen) {
stat = TRUE;
- if (su->su_cache && slen >= 0) {
+ if (su->su_cache) {
cache_set(xprt, (uint32_t) slen);
}
}
diff --git a/src/util/support/threads.c b/src/util/support/threads.c
index be7e4c2e3f..4ded805b79 100644
--- a/src/util/support/threads.c
+++ b/src/util/support/threads.c
@@ -118,7 +118,6 @@ struct tsd_block {
# pragma weak pthread_mutex_destroy
# pragma weak pthread_mutex_init
# pragma weak pthread_self
-# pragma weak pthread_equal
# pragma weak pthread_getspecific
# pragma weak pthread_setspecific
# pragma weak pthread_key_create
@@ -151,7 +150,6 @@ int krb5int_pthread_loaded (void)
|| &pthread_mutex_destroy == 0
|| &pthread_mutex_init == 0
|| &pthread_self == 0
- || &pthread_equal == 0
/* Any program that's really multithreaded will have to be
able to create threads. */
|| &pthread_create == 0
--
2.46.0

@ -0,0 +1,222 @@
From de01999b35773196749ba714f233649c9528aaad Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Thu, 14 Jan 2021 18:13:09 -0500
Subject: [PATCH] Add APIs for marshalling credentials
Faciliate KCM daemon implementations by providing functions to
deserialize and reserialize credentials in the FILE v4 format.
[ghudson@mit.edu: minor editorial changes]
ticket: 8980 (new)
(cherry picked from commit 18ea3bd2fca55b789b7de9c663624bc11d348fa6)
(cherry picked from commit 3d11179707923b033fa413387a33296b673ff52d)
[rharwood@redhat.com: function backport, so conflict in krb5_32.def]
---
doc/appdev/refs/api/index.rst | 2 ++
src/include/krb5/krb5.hin | 36 ++++++++++++++++++++++
src/lib/krb5/ccache/ccmarshal.c | 53 +++++++++++++++++++++++++++++++++
src/lib/krb5/ccache/t_marshal.c | 15 +++++++++-
src/lib/krb5/libkrb5.exports | 2 ++
src/lib/krb5_32.def | 4 +++
6 files changed, 111 insertions(+), 1 deletion(-)
diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst
index 727d9b492..9e03fd386 100644
--- a/doc/appdev/refs/api/index.rst
+++ b/doc/appdev/refs/api/index.rst
@@ -232,6 +232,7 @@ Rarely used public interfaces
krb5_kt_remove_entry.rst
krb5_kt_start_seq_get.rst
krb5_make_authdata_kdc_issued.rst
+ krb5_marshal_credentials.rst
krb5_merge_authdata.rst
krb5_mk_1cred.rst
krb5_mk_error.rst
@@ -285,6 +286,7 @@ Rarely used public interfaces
krb5_tkt_creds_get_times.rst
krb5_tkt_creds_init.rst
krb5_tkt_creds_step.rst
+ krb5_unmarshal_credentials.rst
krb5_verify_init_creds.rst
krb5_verify_init_creds_opt_init.rst
krb5_verify_init_creds_opt_set_ap_req_nofail.rst
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 9264bede1..d2cf1eba2 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -3125,6 +3125,42 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
krb5_ccache ccache, krb5_creds *in_creds,
krb5_creds **out_creds);
+/**
+ * Serialize a @c krb5_creds object.
+ *
+ * @param [in] context Library context
+ * @param [in] creds The credentials object to serialize
+ * @param [out] data_out The serialized credentials
+ *
+ * Serialize @a creds in the format used by the FILE ccache format (vesion 4)
+ * and KCM ccache protocol.
+ *
+ * Use krb5_free_data() to free @a data_out when it is no longer needed.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_marshal_credentials(krb5_context context, krb5_creds *in_creds,
+ krb5_data **data_out);
+
+/**
+ * Deserialize a @c krb5_creds object.
+ *
+ * @param [in] context Library context
+ * @param [in] data The serialized credentials
+ * @param [out] creds_out The resulting creds object
+ *
+ * Deserialize @a data to credentials in the format used by the FILE ccache
+ * format (vesion 4) and KCM ccache protocol.
+ *
+ * Use krb5_free_creds() to free @a creds_out when it is no longer needed.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_unmarshal_credentials(krb5_context context, const krb5_data *data,
+ krb5_creds **creds_out);
+
/** @deprecated Replaced by krb5_get_validated_creds. */
krb5_error_code KRB5_CALLCONV
krb5_get_credentials_validate(krb5_context context, krb5_flags options,
diff --git a/src/lib/krb5/ccache/ccmarshal.c b/src/lib/krb5/ccache/ccmarshal.c
index ae634ccab..ab284e721 100644
--- a/src/lib/krb5/ccache/ccmarshal.c
+++ b/src/lib/krb5/ccache/ccmarshal.c
@@ -515,3 +515,56 @@ k5_marshal_mcred(struct k5buf *buf, krb5_creds *mcred)
if (mcred->second_ticket.length > 0)
put_data(buf, version, &mcred->second_ticket);
}
+
+krb5_error_code KRB5_CALLCONV
+krb5_marshal_credentials(krb5_context context, krb5_creds *in_creds,
+ krb5_data **data_out)
+{
+ krb5_error_code ret;
+ krb5_data *data;
+ struct k5buf buf;
+
+ *data_out = NULL;
+
+ data = k5alloc(sizeof(krb5_data), &ret);
+ if (ret)
+ return ret;
+
+ k5_buf_init_dynamic(&buf);
+ k5_marshal_cred(&buf, 4, in_creds);
+
+ ret = k5_buf_status(&buf);
+ if (ret) {
+ free(data);
+ return ret;
+ }
+
+ /* Steal payload from buf. */
+ *data = make_data(buf.data, buf.len);
+ *data_out = data;
+ return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_unmarshal_credentials(krb5_context context, const krb5_data *data,
+ krb5_creds **creds_out)
+{
+ krb5_error_code ret;
+ krb5_creds *creds;
+
+ *creds_out = NULL;
+
+ creds = k5alloc(sizeof(krb5_creds), &ret);
+ if (ret)
+ return ret;
+
+ ret = k5_unmarshal_cred((unsigned char *)data->data, data->length, 4,
+ creds);
+ if (ret) {
+ free(creds);
+ return ret;
+ }
+
+ *creds_out = creds;
+ return 0;
+}
diff --git a/src/lib/krb5/ccache/t_marshal.c b/src/lib/krb5/ccache/t_marshal.c
index 144554c30..47ec2e94d 100644
--- a/src/lib/krb5/ccache/t_marshal.c
+++ b/src/lib/krb5/ccache/t_marshal.c
@@ -268,13 +268,14 @@ main(int argc, char **argv)
krb5_context context;
krb5_ccache cache;
krb5_principal princ;
- krb5_creds cred1, cred2;
+ krb5_creds cred1, cred2, *alloc_cred;
krb5_cc_cursor cursor;
const char *filename;
char *ccname, filebuf[256];
int version, fd;
const struct test *t;
struct k5buf buf;
+ krb5_data ser_data, *alloc_data;
if (argc != 2)
abort();
@@ -285,6 +286,18 @@ main(int argc, char **argv)
if (krb5_init_context(&context) != 0)
abort();
+ /* Test public functions for unmarshalling and marshalling. */
+ ser_data = make_data((char *)tests[3].cred1, tests[3].cred1len);
+ if (krb5_unmarshal_credentials(context, &ser_data, &alloc_cred) != 0)
+ abort();
+ verify_cred1(alloc_cred);
+ if (krb5_marshal_credentials(context, alloc_cred, &alloc_data) != 0)
+ abort();
+ assert(alloc_data->length == tests[3].cred1len);
+ assert(memcmp(tests[3].cred1, alloc_data->data, alloc_data->length) == 0);
+ krb5_free_data(context, alloc_data);
+ krb5_free_creds(context, alloc_cred);
+
for (version = FIRST_VERSION; version <= 4; version++) {
t = &tests[version - 1];
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index cab5b3b17..48ae46f5c 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -488,6 +488,7 @@ krb5_lock_file
krb5_make_authdata_kdc_issued
krb5_make_full_ipaddr
krb5_make_fulladdr
+krb5_marshal_credentials
krb5_mcc_ops
krb5_merge_authdata
krb5_mk_1cred
@@ -592,6 +593,7 @@ krb5_timeofday
krb5_timestamp_to_sfstring
krb5_timestamp_to_string
krb5_unlock_file
+krb5_unmarshal_credentials
krb5_unpack_full_ipaddr
krb5_unparse_name
krb5_unparse_name_ext
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
index de5823c17..209c6aaef 100644
--- a/src/lib/krb5_32.def
+++ b/src/lib/krb5_32.def
@@ -502,3 +502,7 @@ EXPORTS
; new in 1.19
k5_cc_store_primary_cred @470 ; PRIVATE
+
+; new in 1.20
+ krb5_marshal_credentials @472
+ krb5_unmarshal_credentials @473

@ -0,0 +1,360 @@
From d4a512e571a93318d37cbf7d18a120f317b87e97 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 11 Feb 2021 15:33:10 +0100
Subject: [PATCH] Add KCM_OP_GET_CRED_LIST for faster iteration
For large caches, one IPC operation per credential dominates the cost
of iteration. Instead transfer the whole list of credentials to the
client in one IPC operation.
Add optional support for the new opcode to the test KCM server to
allow testing of the main and fallback code paths.
[ghudson@mit.edu: fixed memory leaks and potential memory errors;
adjusted code style and comments; rewrote commit message; added
kcmserver.py support and tests]
ticket: 8990 (new)
(cherry picked from commit 81bdb47d8ded390263d8ee48f71d5c312b4f1736)
(cherry picked from commit a0ee8b02e56c65e5dcd569caed0e151cef004ef4)
(cherry picked from commit baf60dbdeceb3cad35cad7d9930782f94b6c8221)
---
src/include/kcm.h | 12 ++-
src/lib/krb5/ccache/cc_kcm.c | 144 ++++++++++++++++++++++++++++++++---
src/tests/kcmserver.py | 28 ++++++-
src/tests/t_ccache.py | 10 ++-
4 files changed, 175 insertions(+), 19 deletions(-)
diff --git a/src/include/kcm.h b/src/include/kcm.h
index 5ea1447cd..e4140c3a0 100644
--- a/src/include/kcm.h
+++ b/src/include/kcm.h
@@ -51,9 +51,9 @@
*
* All replies begin with a 32-bit big-endian reply code.
*
- * Parameters are appended to the request or reply with no delimiters. Flags
- * and time offsets are stored as 32-bit big-endian integers. Names are
- * marshalled as zero-terminated strings. Principals and credentials are
+ * Parameters are appended to the request or reply with no delimiters. Flags,
+ * time offsets, and lengths are stored as 32-bit big-endian integers. Names
+ * are marshalled as zero-terminated strings. Principals and credentials are
* marshalled in the v4 FILE ccache format. UUIDs are 16 bytes. UUID lists
* are not delimited, so nothing can come after them.
*/
@@ -89,7 +89,11 @@ typedef enum kcm_opcode {
KCM_OP_HAVE_NTLM_CRED,
KCM_OP_DEL_NTLM_CRED,
KCM_OP_DO_NTLM_AUTH,
- KCM_OP_GET_NTLM_USER_LIST
+ KCM_OP_GET_NTLM_USER_LIST,
+
+ /* MIT extensions */
+ KCM_OP_MIT_EXTENSION_BASE = 13000,
+ KCM_OP_GET_CRED_LIST, /* (name) -> (count, count*{len, cred}) */
} kcm_opcode;
#endif /* KCM_H */
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
index a76a285d9..197a10fba 100644
--- a/src/lib/krb5/ccache/cc_kcm.c
+++ b/src/lib/krb5/ccache/cc_kcm.c
@@ -61,6 +61,17 @@ struct uuid_list {
size_t pos;
};
+struct cred_list {
+ krb5_creds *creds;
+ size_t count;
+ size_t pos;
+};
+
+struct kcm_cursor {
+ struct uuid_list *uuids;
+ struct cred_list *creds;
+};
+
struct kcmio {
SOCKET fd;
#ifdef __APPLE__
@@ -489,6 +500,69 @@ free_uuid_list(struct uuid_list *uuids)
free(uuids);
}
+static void
+free_cred_list(struct cred_list *list)
+{
+ size_t i;
+
+ if (list == NULL)
+ return;
+
+ /* Creds are transferred to the caller as list->pos is incremented, so we
+ * can start freeing there. */
+ for (i = list->pos; i < list->count; i++)
+ krb5_free_cred_contents(NULL, &list->creds[i]);
+ free(list->creds);
+ free(list);
+}
+
+/* Fetch a cred list from req->reply. */
+static krb5_error_code
+kcmreq_get_cred_list(struct kcmreq *req, struct cred_list **creds_out)
+{
+ struct cred_list *list;
+ const unsigned char *data;
+ krb5_error_code ret = 0;
+ size_t count, len, i;
+
+ *creds_out = NULL;
+
+ /* Check a rough bound on the count to prevent very large allocations. */
+ count = k5_input_get_uint32_be(&req->reply);
+ if (count > req->reply.len / 4)
+ return KRB5_KCM_MALFORMED_REPLY;
+
+ list = malloc(sizeof(*list));
+ if (list == NULL)
+ return ENOMEM;
+
+ list->creds = NULL;
+ list->count = count;
+ list->pos = 0;
+ list->creds = k5calloc(count, sizeof(*list->creds), &ret);
+ if (list->creds == NULL) {
+ free(list);
+ return ret;
+ }
+
+ for (i = 0; i < count; i++) {
+ len = k5_input_get_uint32_be(&req->reply);
+ data = k5_input_get_bytes(&req->reply, len);
+ if (data == NULL)
+ break;
+ ret = k5_unmarshal_cred(data, len, 4, &list->creds[i]);
+ if (ret)
+ break;
+ }
+ if (i < count) {
+ free_cred_list(list);
+ return (ret == ENOMEM) ? ENOMEM : KRB5_KCM_MALFORMED_REPLY;
+ }
+
+ *creds_out = list;
+ return 0;
+}
+
static void
kcmreq_free(struct kcmreq *req)
{
@@ -753,33 +827,53 @@ kcm_start_seq_get(krb5_context context, krb5_ccache cache,
{
krb5_error_code ret;
struct kcmreq req = EMPTY_KCMREQ;
- struct uuid_list *uuids;
+ struct uuid_list *uuids = NULL;
+ struct cred_list *creds = NULL;
+ struct kcm_cursor *cursor;
*cursor_out = NULL;
get_kdc_offset(context, cache);
- kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
+ kcmreq_init(&req, KCM_OP_GET_CRED_LIST, cache);
ret = cache_call(context, cache, &req);
- if (ret)
+ if (ret == 0) {
+ /* GET_CRED_LIST is available. */
+ ret = kcmreq_get_cred_list(&req, &creds);
+ if (ret)
+ goto cleanup;
+ } else if (ret == KRB5_FCC_INTERNAL) {
+ /* Fall back to GET_CRED_UUID_LIST. */
+ kcmreq_free(&req);
+ kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
+ ret = cache_call(context, cache, &req);
+ if (ret)
+ goto cleanup;
+ ret = kcmreq_get_uuid_list(&req, &uuids);
+ if (ret)
+ goto cleanup;
+ } else {
goto cleanup;
- ret = kcmreq_get_uuid_list(&req, &uuids);
- if (ret)
+ }
+
+ cursor = k5alloc(sizeof(*cursor), &ret);
+ if (cursor == NULL)
goto cleanup;
- *cursor_out = (krb5_cc_cursor)uuids;
+ cursor->uuids = uuids;
+ cursor->creds = creds;
+ *cursor_out = (krb5_cc_cursor)cursor;
cleanup:
kcmreq_free(&req);
return ret;
}
-static krb5_error_code KRB5_CALLCONV
-kcm_next_cred(krb5_context context, krb5_ccache cache, krb5_cc_cursor *cursor,
- krb5_creds *cred_out)
+static krb5_error_code
+next_cred_by_uuid(krb5_context context, krb5_ccache cache,
+ struct uuid_list *uuids, krb5_creds *cred_out)
{
krb5_error_code ret;
struct kcmreq req;
- struct uuid_list *uuids = (struct uuid_list *)*cursor;
memset(cred_out, 0, sizeof(*cred_out));
@@ -797,11 +891,39 @@ kcm_next_cred(krb5_context context, krb5_ccache cache, krb5_cc_cursor *cursor,
return map_invalid(ret);
}
+static krb5_error_code KRB5_CALLCONV
+kcm_next_cred(krb5_context context, krb5_ccache cache, krb5_cc_cursor *cursor,
+ krb5_creds *cred_out)
+{
+ struct kcm_cursor *c = (struct kcm_cursor *)*cursor;
+ struct cred_list *list;
+
+ if (c->uuids != NULL)
+ return next_cred_by_uuid(context, cache, c->uuids, cred_out);
+
+ list = c->creds;
+ if (list->pos >= list->count)
+ return KRB5_CC_END;
+
+ /* Transfer memory ownership of one cred to the caller. */
+ *cred_out = list->creds[list->pos];
+ memset(&list->creds[list->pos], 0, sizeof(*list->creds));
+ list->pos++;
+
+ return 0;
+}
+
static krb5_error_code KRB5_CALLCONV
kcm_end_seq_get(krb5_context context, krb5_ccache cache,
krb5_cc_cursor *cursor)
{
- free_uuid_list((struct uuid_list *)*cursor);
+ struct kcm_cursor *c = *cursor;
+
+ if (c == NULL)
+ return 0;
+ free_uuid_list(c->uuids);
+ free_cred_list(c->creds);
+ free(c);
*cursor = NULL;
return 0;
}
diff --git a/src/tests/kcmserver.py b/src/tests/kcmserver.py
index 57432e5a7..8c5e66ff1 100644
--- a/src/tests/kcmserver.py
+++ b/src/tests/kcmserver.py
@@ -23,6 +23,7 @@
# traceback.print_exception(etype, value, tb, file=f)
# sys.excepthook = ehook
+import optparse
import select
import socket
import struct
@@ -49,12 +50,14 @@ class KCMOpcodes(object):
SET_DEFAULT_CACHE = 21
GET_KDC_OFFSET = 22
SET_KDC_OFFSET = 23
+ GET_CRED_LIST = 13001
class KRB5Errors(object):
KRB5_CC_END = -1765328242
KRB5_CC_NOSUPP = -1765328137
KRB5_FCC_NOFILE = -1765328189
+ KRB5_FCC_INTERNAL = -1765328188
def make_uuid():
@@ -183,6 +186,14 @@ def op_set_kdc_offset(argbytes):
return 0, b''
+def op_get_cred_list(argbytes):
+ name, rest = unmarshal_name(argbytes)
+ cache = get_cache(name)
+ creds = [cache.creds[u] for u in cache.cred_uuids]
+ return 0, (struct.pack('>L', len(creds)) +
+ b''.join(struct.pack('>L', len(c)) + c for c in creds))
+
+
ophandlers = {
KCMOpcodes.GEN_NEW : op_gen_new,
KCMOpcodes.INITIALIZE : op_initialize,
@@ -197,7 +208,8 @@ ophandlers = {
KCMOpcodes.GET_DEFAULT_CACHE : op_get_default_cache,
KCMOpcodes.SET_DEFAULT_CACHE : op_set_default_cache,
KCMOpcodes.GET_KDC_OFFSET : op_get_kdc_offset,
- KCMOpcodes.SET_KDC_OFFSET : op_set_kdc_offset
+ KCMOpcodes.SET_KDC_OFFSET : op_set_kdc_offset,
+ KCMOpcodes.GET_CRED_LIST : op_get_cred_list
}
# Read and respond to a request from the socket s.
@@ -215,7 +227,11 @@ def service_request(s):
majver, minver, op = struct.unpack('>BBH', req[:4])
argbytes = req[4:]
- code, payload = ophandlers[op](argbytes)
+
+ if op in ophandlers:
+ code, payload = ophandlers[op](argbytes)
+ else:
+ code, payload = KRB5Errors.KRB5_FCC_INTERNAL, b''
# The KCM response is the code (4 bytes) and the response payload.
# The Heimdal IPC response is the length of the KCM response (4
@@ -226,9 +242,15 @@ def service_request(s):
s.sendall(hipc_response)
return True
+parser = optparse.OptionParser()
+parser.add_option('-c', '--credlist', action='store_true', dest='credlist',
+ default=False, help='Support KCM_OP_GET_CRED_LIST')
+(options, args) = parser.parse_args()
+if not options.credlist:
+ del ophandlers[KCMOpcodes.GET_CRED_LIST]
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-server.bind(sys.argv[1])
+server.bind(args[0])
server.listen(5)
select_input = [server,]
sys.stderr.write('starting...\n')
diff --git a/src/tests/t_ccache.py b/src/tests/t_ccache.py
index 66804afa5..90040fb7b 100755
--- a/src/tests/t_ccache.py
+++ b/src/tests/t_ccache.py
@@ -125,10 +125,18 @@ def collection_test(realm, ccname):
collection_test(realm, 'DIR:' + os.path.join(realm.testdir, 'cc'))
+
+# Test KCM without and with GET_CRED_LIST support.
kcmserver_path = os.path.join(srctop, 'tests', 'kcmserver.py')
-realm.start_server([sys.executable, kcmserver_path, kcm_socket_path],
+kcmd = realm.start_server([sys.executable, kcmserver_path, kcm_socket_path],
+ 'starting...')
+collection_test(realm, 'KCM:')
+stop_daemon(kcmd)
+os.remove(kcm_socket_path)
+realm.start_server([sys.executable, kcmserver_path, '-c', kcm_socket_path],
'starting...')
collection_test(realm, 'KCM:')
+
if test_keyring:
def cleanup_keyring(anchor, name):
out = realm.run(['keyctl', 'list', anchor])

@ -0,0 +1,673 @@
From bf3e55bcd66c5d35fddadc94fd680bdd57508bce 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 c6ea088742..22ef2b2f42 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 8e59628bd9..12a1d441b8 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -8187,6 +8187,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 4fbdbec052..b0666c3b81 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,840 @@
From 48be25aaa27487fcbbba76044083de37211b30e7 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 | 12 ++
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 | 3 +
src/plugins/kdb/test/kdb_test.c | 6 +-
11 files changed, 544 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 001fb386a7..c6ea088742 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 a7060aa733..8e59628bd9 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
@@ -8181,6 +8181,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 */
@@ -8338,56 +8344,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 439ca02725..cd842b03cd 100644
--- a/src/lib/krb5/krb/deps
+++ b/src/lib/krb5/krb/deps
@@ -709,7 +709,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 \
@@ -720,7 +720,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 fe61bebf5b..453ed60c6c 100644
--- a/src/lib/krb5/krb/int-proto.h
+++ b/src/lib/krb5/krb/int-proto.h
@@ -386,4 +386,16 @@ k5_get_proxy_cred_from_kdc(krb5_context context, krb5_flags options,
krb5_ccache ccache, krb5_creds *in_creds,
krb5_creds **out_creds);
+/* Return true if mprinc will match any hostname in a host-based principal name
+ * (possibly due to ignore_acceptor_hostname) with krb5_sname_match(). */
+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 48ae46f5c4..28784ec67c 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -462,6 +462,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 209c6aaef5..8c3469a96c 100644
--- a/src/lib/krb5_32.def
+++ b/src/lib/krb5_32.def
@@ -506,3 +506,6 @@ EXPORTS
; new in 1.20
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 38d371cb86..7d033acae4 100644
--- a/src/plugins/kdb/test/kdb_test.c
+++ b/src/plugins/kdb/test/kdb_test.c
@@ -675,7 +675,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;
@@ -684,7 +684,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;
@@ -697,7 +697,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,169 @@
From 5c2f409c360560c8b99926d6cf1a80419e758b22 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 7 Mar 2023 00:19:33 -0500
Subject: [PATCH] Add a simple DER support header
(cherry picked from commit 548da160b52b25a106e9f6077d6a42c2c049586c)
---
src/include/k5-der.h | 149 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 149 insertions(+)
create mode 100644 src/include/k5-der.h
diff --git a/src/include/k5-der.h b/src/include/k5-der.h
new file mode 100644
index 0000000000..b8371d9b4d
--- /dev/null
+++ b/src/include/k5-der.h
@@ -0,0 +1,149 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* include/k5-der.h - Distinguished Encoding Rules (DER) declarations */
+/*
+ * Copyright (C) 2023 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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.
+ */
+
+/*
+ * Most ASN.1 encoding and decoding is done using the table-driven framework in
+ * libkrb5. When that is not an option, these helpers can be used to encode
+ * and decode simple types.
+ */
+
+#ifndef K5_DER_H
+#define K5_DER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "k5-buf.h"
+#include "k5-input.h"
+
+/* Return the number of bytes needed to encode len as a DER encoding length. */
+static inline size_t
+k5_der_len_len(size_t len)
+{
+ size_t llen;
+
+ if (len < 128)
+ return 1;
+ llen = 1;
+ while (len > 0) {
+ len >>= 8;
+ llen++;
+ }
+ return llen;
+}
+
+/* Return the number of bytes needed to encode a DER value (with identifier
+ * byte and length) for a given contents length. */
+static inline size_t
+k5_der_value_len(size_t contents_len)
+{
+ return 1 + k5_der_len_len(contents_len) + contents_len;
+}
+
+/* Add a DER identifier byte (composed by the caller, including the ASN.1
+ * class, tag, and constructed bit) and length. */
+static inline void
+k5_der_add_taglen(struct k5buf *buf, uint8_t idbyte, size_t len)
+{
+ uint8_t *p;
+ size_t llen = k5_der_len_len(len);
+
+ p = k5_buf_get_space(buf, 1 + llen);
+ if (p == NULL)
+ return;
+ *p++ = idbyte;
+ if (len < 128) {
+ *p = len;
+ } else {
+ *p = 0x80 | (llen - 1);
+ /* Encode the length bytes backwards so the most significant byte is
+ * first. */
+ p += llen;
+ while (len > 0) {
+ *--p = len & 0xFF;
+ len >>= 8;
+ }
+ }
+}
+
+/* Add a DER value (identifier byte, length, and contents). */
+static inline void
+k5_der_add_value(struct k5buf *buf, uint8_t idbyte, const void *contents,
+ size_t len)
+{
+ k5_der_add_taglen(buf, idbyte, len);
+ k5_buf_add_len(buf, contents, len);
+}
+
+/*
+ * If the next byte in in matches idbyte and the subsequent DER length is
+ * valid, advance in past the value, set *contents_out to the value contents,
+ * and return true. Otherwise return false. Only set an error on in if the
+ * next bytes matches idbyte but the ensuing length is invalid. contents_out
+ * may be aliased to in; it will only be written to on successful decoding of a
+ * value.
+ */
+static inline bool
+k5_der_get_value(struct k5input *in, uint8_t idbyte,
+ struct k5input *contents_out)
+{
+ uint8_t lenbyte, i;
+ size_t len;
+ const void *bytes;
+
+ /* Do nothing if in is empty or the next byte doesn't match idbyte. */
+ if (in->status || in->len == 0 || *in->ptr != idbyte)
+ return false;
+
+ /* Advance past the identifier byte and decode the length. */
+ (void)k5_input_get_byte(in);
+ lenbyte = k5_input_get_byte(in);
+ if (lenbyte < 128) {
+ len = lenbyte;
+ } else {
+ len = 0;
+ for (i = 0; i < (lenbyte & 0x7F); i++) {
+ if (len > (SIZE_MAX >> 8)) {
+ k5_input_set_status(in, EOVERFLOW);
+ return false;
+ }
+ len = (len << 8) | k5_input_get_byte(in);
+ }
+ }
+
+ bytes = k5_input_get_bytes(in, len);
+ if (bytes == NULL)
+ return false;
+ k5_input_init(contents_out, bytes, len);
+ return true;
+}
+
+#endif /* K5_DER_H */
--
2.45.1

@ -0,0 +1,420 @@
From 8182f9f08b2593ff8749078ffd3daef9bf39a7fe Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Fri, 20 Mar 2020 00:17:28 +0100
Subject: [PATCH] Add channel bindings tests
[ghudson@mit.edu: adjusted test program to output channel-bound state
instead of optionally enforcing it; adjusted tests to check program
output; split out tests into separate Python script; made cosmetic
changes]
ticket: 8900
(cherry picked from commit b0b21b6d25b06f3e2b365dfe9dd4c99b3d43bf57)
[rharwood@redhat.com: .gitignore]
(cherry picked from commit 3e92520c1417f22447751cd9172d5ab30c2e0ad8)
---
src/plugins/gssapi/negoextest/main.c | 18 +++++
src/tests/gssapi/Makefile.in | 49 ++++++------
src/tests/gssapi/common.c | 25 ++++--
src/tests/gssapi/common.h | 9 +++
src/tests/gssapi/deps | 4 +
src/tests/gssapi/t_bindings.c | 111 +++++++++++++++++++++++++++
src/tests/gssapi/t_bindings.py | 43 +++++++++++
src/tests/gssapi/t_negoex.py | 7 ++
8 files changed, 237 insertions(+), 29 deletions(-)
create mode 100644 src/tests/gssapi/t_bindings.c
create mode 100644 src/tests/gssapi/t_bindings.py
diff --git a/src/plugins/gssapi/negoextest/main.c b/src/plugins/gssapi/negoextest/main.c
index 6c340f41b..72fc5273a 100644
--- a/src/plugins/gssapi/negoextest/main.c
+++ b/src/plugins/gssapi/negoextest/main.c
@@ -57,6 +57,15 @@ gss_init_sec_context(OM_uint32 *minor_status,
const char *envstr;
uint8_t hops, mech_last_octet;
+ envstr = getenv("GSS_INIT_BINDING");
+ if (envstr != NULL) {
+ assert(strlen(envstr) > 0);
+ assert(input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS);
+ assert(strlen(envstr) == input_chan_bindings->application_data.length);
+ assert(strcmp((char *)input_chan_bindings->application_data.value,
+ envstr) == 0);
+ }
+
if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
envstr = getenv("HOPS");
hops = (envstr != NULL) ? atoi(envstr) : 1;
@@ -112,6 +121,15 @@ gss_accept_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle,
uint8_t hops, mech_last_octet;
const char *envstr;
+ envstr = getenv("GSS_ACCEPT_BINDING");
+ if (envstr != NULL) {
+ assert(strlen(envstr) > 0);
+ assert(input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS);
+ assert(strlen(envstr) == input_chan_bindings->application_data.length);
+ assert(strcmp((char *)input_chan_bindings->application_data.value,
+ envstr) == 0);
+ }
+
/*
* The unwrapped token sits at the end and is just one byte giving the
* remaining number of hops. The final octet of the mech encoding should
diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in
index 5cc1e0f58..68c132b79 100644
--- a/src/tests/gssapi/Makefile.in
+++ b/src/tests/gssapi/Makefile.in
@@ -9,33 +9,33 @@ LOCALINCLUDES = -I$(srcdir)/../../lib/gssapi/mechglue \
-I../../lib/gssapi/generic
SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \
- $(srcdir)/t_accname.c $(srcdir)/t_add_cred.c $(srcdir)/t_ccselect.c \
- $(srcdir)/t_ciflags.c $(srcdir)/t_context.c $(srcdir)/t_credstore.c \
- $(srcdir)/t_enctypes.c $(srcdir)/t_err.c $(srcdir)/t_export_cred.c \
- $(srcdir)/t_export_name.c $(srcdir)/t_gssexts.c \
- $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c $(srcdir)/t_invalid.c \
- $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \
+ $(srcdir)/t_accname.c $(srcdir)/t_add_cred.c $(srcdir)/t_bindings.c \
+ $(srcdir)/t_ccselect.c $(srcdir)/t_ciflags.c $(srcdir)/t_context.c \
+ $(srcdir)/t_credstore.c $(srcdir)/t_enctypes.c $(srcdir)/t_err.c \
+ $(srcdir)/t_export_cred.c $(srcdir)/t_export_name.c \
+ $(srcdir)/t_gssexts.c $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c \
+ $(srcdir)/t_invalid.c $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \
$(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \
$(srcdir)/t_lifetime.c $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c \
$(srcdir)/t_pcontok.c $(srcdir)/t_prf.c $(srcdir)/t_s4u.c \
$(srcdir)/t_s4u2proxy_krb5.c $(srcdir)/t_saslname.c \
$(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c
-OBJS= ccinit.o ccrefresh.o common.o t_accname.o t_add_cred.o t_ccselect.o \
- t_ciflags.o t_context.o t_credstore.o t_enctypes.o t_err.o \
- t_export_cred.o t_export_name.o t_gssexts.o t_imp_cred.o t_imp_name.o \
- t_invalid.o t_inq_cred.o t_inq_ctx.o t_inq_mechs_name.o t_iov.o \
- t_lifetime.o t_namingexts.o t_oid.o t_pcontok.o t_prf.o t_s4u.o \
- t_s4u2proxy_krb5.o t_saslname.o t_spnego.o t_srcattrs.o
+OBJS= ccinit.o ccrefresh.o common.o t_accname.o t_add_cred.o t_bindings.o \
+ t_ccselect.o t_ciflags.o t_context.o t_credstore.o t_enctypes.o \
+ t_err.o t_export_cred.o t_export_name.o t_gssexts.o t_imp_cred.o \
+ t_imp_name.o t_invalid.o t_inq_cred.o t_inq_ctx.o t_inq_mechs_name.o \
+ t_iov.o t_lifetime.o t_namingexts.o t_oid.o t_pcontok.o t_prf.o \
+ t_s4u.o t_s4u2proxy_krb5.o t_saslname.o t_spnego.o t_srcattrs.o
COMMON_DEPS= common.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
COMMON_LIBS= common.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
-all: ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags t_context \
- t_credstore t_enctypes t_err t_export_cred t_export_name t_gssexts \
- t_imp_cred t_imp_name t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name \
- t_iov t_lifetime t_namingexts t_oid t_pcontok t_prf t_s4u \
- t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs
+all: ccinit ccrefresh t_accname t_add_cred t_bindings t_ccselect t_ciflags \
+ t_context t_credstore t_enctypes t_err t_export_cred t_export_name \
+ t_gssexts t_imp_cred t_imp_name t_invalid t_inq_cred t_inq_ctx \
+ t_inq_mechs_name t_iov t_lifetime t_namingexts t_oid t_pcontok t_prf \
+ t_s4u t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs
check-unix: t_oid
$(RUN_TEST) ./t_invalid
@@ -43,11 +43,12 @@ check-unix: t_oid
$(RUN_TEST) ./t_prf
$(RUN_TEST) ./t_imp_name
-check-pytests: ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags \
- t_context t_credstore t_enctypes t_err t_export_cred t_export_name \
- t_imp_cred t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime \
- t_pcontok t_s4u t_s4u2proxy_krb5 t_spnego t_srcattrs
+check-pytests: ccinit ccrefresh t_accname t_add_cred t_bindings t_ccselect \
+ t_ciflags t_context t_credstore t_enctypes t_err t_export_cred \
+ t_export_name t_imp_cred t_inq_cred t_inq_ctx t_inq_mechs_name t_iov \
+ t_lifetime t_pcontok t_s4u t_s4u2proxy_krb5 t_spnego t_srcattrs
$(RUNPYTEST) $(srcdir)/t_gssapi.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_bindings.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_ccselect.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_client_keytab.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_enctypes.py $(PYTESTFLAGS)
@@ -64,6 +65,8 @@ t_accname: t_accname.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_accname.o $(COMMON_LIBS)
t_add_cred: t_add_cred.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_add_cred.o $(COMMON_LIBS)
+t_bindings: t_bindings.o $(COMMON_DEPS)
+ $(CC_LINK) -o $@ t_bindings.o $(COMMON_LIBS)
t_ccselect: t_ccselect.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_ccselect.o $(COMMON_LIBS)
t_ciflags: t_ciflags.o $(COMMON_DEPS)
@@ -118,8 +121,8 @@ t_srcattrs: t_srcattrs.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_srcattrs.o $(COMMON_LIBS)
clean:
- $(RM) ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags
- $(RM) t_context t_credstore t_enctypes t_err t_export_cred
+ $(RM) ccinit ccrefresh t_accname t_add_cred t_bindings t_ccselect
+ $(RM) t_ciflags t_context t_credstore t_enctypes t_err t_export_cred
$(RM) t_export_name t_gssexts t_imp_cred t_imp_name t_invalid
$(RM) t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime
$(RM) t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5
diff --git a/src/tests/gssapi/common.c b/src/tests/gssapi/common.c
index 83e9d9bb8..7ba72f7b2 100644
--- a/src/tests/gssapi/common.c
+++ b/src/tests/gssapi/common.c
@@ -115,6 +115,20 @@ establish_contexts(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ictx,
gss_ctx_id_t *actx, gss_name_t *src_name, gss_OID *amech,
gss_cred_id_t *deleg_cred)
+{
+ return establish_contexts_ex(imech, icred, acred, tname, flags, ictx, actx,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_CHANNEL_BINDINGS, NULL, src_name,
+ amech, deleg_cred);
+}
+
+void
+establish_contexts_ex(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
+ gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ictx,
+ gss_ctx_id_t *actx, gss_channel_bindings_t icb,
+ gss_channel_bindings_t acb, OM_uint32 *aret_flags,
+ gss_name_t *src_name, gss_OID *amech,
+ gss_cred_id_t *deleg_cred)
{
OM_uint32 minor, imaj, amaj;
gss_buffer_desc itok, atok;
@@ -126,17 +140,16 @@ establish_contexts(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
for (;;) {
(void)gss_release_buffer(&minor, &itok);
imaj = gss_init_sec_context(&minor, icred, ictx, tname, imech, flags,
- GSS_C_INDEFINITE,
- GSS_C_NO_CHANNEL_BINDINGS, &atok, NULL,
- &itok, NULL, NULL);
+ GSS_C_INDEFINITE, icb, &atok, NULL, &itok,
+ NULL, NULL);
check_gsserr("gss_init_sec_context", imaj, minor);
if (amaj == GSS_S_COMPLETE)
break;
(void)gss_release_buffer(&minor, &atok);
- amaj = gss_accept_sec_context(&minor, actx, acred, &itok,
- GSS_C_NO_CHANNEL_BINDINGS, src_name,
- amech, &atok, NULL, NULL, deleg_cred);
+ amaj = gss_accept_sec_context(&minor, actx, acred, &itok, acb,
+ src_name, amech, &atok, aret_flags, NULL,
+ deleg_cred);
check_gsserr("gss_accept_sec_context", amaj, minor);
(void)gss_release_buffer(&minor, &itok);
if (imaj == GSS_S_COMPLETE)
diff --git a/src/tests/gssapi/common.h b/src/tests/gssapi/common.h
index ae11b51d4..a5c8f87e6 100644
--- a/src/tests/gssapi/common.h
+++ b/src/tests/gssapi/common.h
@@ -62,6 +62,15 @@ void establish_contexts(gss_OID imech, gss_cred_id_t icred,
gss_name_t *src_name, gss_OID *amech,
gss_cred_id_t *deleg_cred);
+/* Establish contexts with channel bindings. */
+void establish_contexts_ex(gss_OID imech, gss_cred_id_t icred,
+ gss_cred_id_t acred, gss_name_t tname,
+ OM_uint32 flags, gss_ctx_id_t *ictx,
+ gss_ctx_id_t *actx, gss_channel_bindings_t icb,
+ gss_channel_bindings_t acb, OM_uint32 *aret_flags,
+ gss_name_t *src_name, gss_OID *amech,
+ gss_cred_id_t *deleg_cred);
+
/* Export *cred to a token, then release *cred and replace it by re-importing
* the token. */
void export_import_cred(gss_cred_id_t *cred);
diff --git a/src/tests/gssapi/deps b/src/tests/gssapi/deps
index acd0e96f8..73e4d9a74 100644
--- a/src/tests/gssapi/deps
+++ b/src/tests/gssapi/deps
@@ -33,6 +33,10 @@ $(OUTPRE)t_add_cred.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
$(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
$(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
common.h t_add_cred.c
+$(OUTPRE)t_bindings.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
+ common.h t_bindings.c
$(OUTPRE)t_ccselect.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
$(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
$(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
diff --git a/src/tests/gssapi/t_bindings.c b/src/tests/gssapi/t_bindings.c
new file mode 100644
index 000000000..e8906715b
--- /dev/null
+++ b/src/tests/gssapi/t_bindings.c
@@ -0,0 +1,111 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2020 by Red Hat, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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 <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "common.h"
+
+/*
+ * Establish contexts (without and with GSS_C_DCE_STYLE) with the default
+ * initiator name, a specified principal name as target name, initiator
+ * bindings, and acceptor bindings. If any call is unsuccessful, display an
+ * error message. Output "yes" or "no" to indicate whether the contexts were
+ * reported as channel-bound on the acceptor. Exit with status 0 if all
+ * operations are successful, or 1 if not.
+ *
+ * Usage: ./t_bindings [-s] targetname icb acb
+ *
+ * An icb or abc value of "-" will not specify channel bindings.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ OM_uint32 minor, flags1, flags2;
+ gss_name_t target_name;
+ gss_ctx_id_t ictx, actx;
+ struct gss_channel_bindings_struct icb_data = {0}, acb_data = {0};
+ gss_channel_bindings_t icb = GSS_C_NO_CHANNEL_BINDINGS;
+ gss_channel_bindings_t acb = GSS_C_NO_CHANNEL_BINDINGS;
+ gss_OID_desc *mech;
+
+ argv++;
+ argc--;
+ if (*argv != NULL && strcmp(*argv, "-s") == 0) {
+ mech = &mech_spnego;
+ argv++;
+ argc--;
+ } else {
+ mech = &mech_krb5;
+ }
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: t_bindings [-s] targetname icb acb\n");
+ return 1;
+ }
+
+ target_name = import_name(argv[0]);
+
+ if (strcmp(argv[1], "-") != 0) {
+ icb_data.application_data.length = strlen(argv[1]);
+ icb_data.application_data.value = argv[1];
+ icb = &icb_data;
+ }
+
+ if (strcmp(argv[2], "-") != 0) {
+ acb_data.application_data.length = strlen(argv[2]);
+ acb_data.application_data.value = argv[2];
+ acb = &acb_data;
+ }
+
+ establish_contexts_ex(mech, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL,
+ target_name, 0, &ictx, &actx, icb, acb, &flags1,
+ NULL, NULL, NULL);
+
+ /* Try again with GSS_C_DCE_STYLE */
+ (void)gss_delete_sec_context(&minor, &ictx, NULL);
+ (void)gss_delete_sec_context(&minor, &actx, NULL);
+
+ establish_contexts_ex(mech, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL,
+ target_name, GSS_C_DCE_STYLE, &ictx, &actx, icb, acb,
+ &flags2, NULL, NULL, NULL);
+ assert((flags1 & GSS_C_CHANNEL_BOUND_FLAG) ==
+ (flags2 & GSS_C_CHANNEL_BOUND_FLAG));
+ printf("%s\n", (flags1 & GSS_C_CHANNEL_BOUND_FLAG) ? "yes" : "no");
+
+ (void)gss_delete_sec_context(&minor, &ictx, NULL);
+ (void)gss_delete_sec_context(&minor, &actx, NULL);
+ (void)gss_release_name(&minor, &target_name);
+
+ return 0;
+}
diff --git a/src/tests/gssapi/t_bindings.py b/src/tests/gssapi/t_bindings.py
new file mode 100644
index 000000000..f377977b6
--- /dev/null
+++ b/src/tests/gssapi/t_bindings.py
@@ -0,0 +1,43 @@
+from k5test import *
+
+realm = K5Realm()
+server = 'p:' + realm.host_princ
+
+mark('krb5 channel bindings')
+realm.run(['./t_bindings', server, '-', '-'], expected_msg='no')
+realm.run(['./t_bindings', server, 'a', '-'], expected_msg='no')
+realm.run(['./t_bindings', server, 'a', 'a'], expected_msg='yes')
+realm.run(['./t_bindings', server, '-', 'a'], expected_msg='no')
+realm.run(['./t_bindings', server, 'a', 'x'],
+ expected_code=1, expected_msg='Incorrect channel bindings')
+
+mark('SPNEGO channel bindings')
+realm.run(['./t_bindings', '-s', server, '-', '-'], expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', '-'], expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', 'a'], expected_msg='yes')
+realm.run(['./t_bindings', '-s', server, '-', 'a'], expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', 'x'],
+ expected_code=1, expected_msg='Incorrect channel bindings')
+
+client_aware_conf = {'libdefaults': {'client_aware_channel_bindings': 'true'}}
+e = realm.special_env('cb_aware', False, krb5_conf=client_aware_conf)
+
+mark('krb5 client_aware_channel_bindings')
+realm.run(['./t_bindings', server, '-', '-'], env=e, expected_msg='no')
+realm.run(['./t_bindings', server, 'a', '-'], env=e, expected_msg='no')
+realm.run(['./t_bindings', server, 'a', 'a'], env=e, expected_msg='yes')
+realm.run(['./t_bindings', server, '-', 'a'], env=e,
+ expected_code=1, expected_msg='Incorrect channel bindings')
+realm.run(['./t_bindings', server, 'a', 'x'], env=e,
+ expected_code=1, expected_msg='Incorrect channel bindings')
+
+mark('SPNEGO client_aware_channel_bindings')
+realm.run(['./t_bindings', '-s', server, '-', '-'], env=e, expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', '-'], env=e, expected_msg='no')
+realm.run(['./t_bindings', '-s', server, 'a', 'a'], env=e, expected_msg='yes')
+realm.run(['./t_bindings', '-s', server, '-', 'a'], env=e,
+ expected_code=1, expected_msg='Incorrect channel bindings')
+realm.run(['./t_bindings', '-s', server, 'a', 'x'], env=e,
+ expected_code=1, expected_msg='Incorrect channel bindings')
+
+success('channel bindings tests')
diff --git a/src/tests/gssapi/t_negoex.py b/src/tests/gssapi/t_negoex.py
index 88470d2fa..a218899c4 100644
--- a/src/tests/gssapi/t_negoex.py
+++ b/src/tests/gssapi/t_negoex.py
@@ -139,4 +139,11 @@ msgs = ('sending [3]AP_REQUEST', 'sending [7]CHALLENGE', 'sending [8]VERIFY',
'sending [11]CHALLENGE', 'sending [12]VERIFY', 'sending [13]VERIFY')
test({'HOPS': '4', 'KEY': 'accept-always'}, expected_trace=())
+mark('channel bindings')
+e = realm.env.copy()
+e.update({'HOPS': '1', 'GSS_INIT_BINDING': 'a', 'GSS_ACCEPT_BINDING': 'b'})
+# The test mech will verify that the bindings are communicated to the
+# mech, but does not set the channel-bound flag.
+realm.run(['./t_bindings', '-s', 'h:host', 'a', 'b'], env=e, expected_msg='no')
+
success('NegoEx tests')

@ -0,0 +1,265 @@
From 64f643a7f798c5528182dc068f15dca7b3f2d8a1 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Tue, 10 Mar 2020 13:13:17 +0100
Subject: [PATCH] Add client_aware_channel_bindings option
Add client support for KERB_AP_OPTIONS_CBT in the form of a profile
option "client_aware_gss_bindings". Adjust the make_etype_list()
helper so that enctype negotiation and AP_OPTIONS can be included in
the same IF-RELEVANT wrapper.
[ghudson@mit.edu: refactored; edited documentation; wrote commit
message]
ticket: 8900
(cherry picked from commit 225e6ef7f021cd1a8ef2a054af0ca58b7288fd81)
(cherry picked from commit 2a08fe3d2d1972df4ffe37d4bb64b161889ff988)
---
doc/admin/conf_files/krb5_conf.rst | 6 +
src/include/k5-int.h | 1 +
src/lib/krb5/krb/mk_req_ext.c | 177 +++++++++++++++--------------
3 files changed, 98 insertions(+), 86 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 3a8b9cf47..315253e37 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -389,6 +389,12 @@ The libdefaults section may contain any of the following relations:
credentials will fail if the client machine does not have a
keytab. The default value is false.
+**client_aware_channel_bindings**
+ If this flag is true, then all application protocol authentication
+ requests will be flagged to indicate that the application supports
+ channel bindings when operating over a secure channel. The
+ default value is false.
+
.. _realms:
[realms]
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 0d9af3d95..eb18a4cd6 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -299,6 +299,7 @@ typedef unsigned char u_char;
#define KRB5_CONF_V4_INSTANCE_CONVERT "v4_instance_convert"
#define KRB5_CONF_V4_REALM "v4_realm"
#define KRB5_CONF_VERIFY_AP_REQ_NOFAIL "verify_ap_req_nofail"
+#define KRB5_CONF_CLIENT_AWARE_GSS_BINDINGS "client_aware_channel_bindings"
/* Cache configuration variables */
#define KRB5_CC_CONF_FAST_AVAIL "fast_avail"
diff --git a/src/lib/krb5/krb/mk_req_ext.c b/src/lib/krb5/krb/mk_req_ext.c
index 9fc6a0e52..08504860c 100644
--- a/src/lib/krb5/krb/mk_req_ext.c
+++ b/src/lib/krb5/krb/mk_req_ext.c
@@ -68,10 +68,9 @@
*/
static krb5_error_code
-make_etype_list(krb5_context context,
- krb5_enctype *desired_etypes,
- krb5_enctype tkt_enctype,
- krb5_authdata ***authdata);
+make_ap_authdata(krb5_context context, krb5_enctype *desired_enctypes,
+ krb5_enctype tkt_enctype, krb5_boolean client_aware_cb,
+ krb5_authdata ***authdata_out);
static krb5_error_code
generate_authenticator(krb5_context,
@@ -263,7 +262,8 @@ generate_authenticator(krb5_context context, krb5_authenticator *authent,
krb5_enctype tkt_enctype)
{
krb5_error_code retval;
- krb5_authdata **ext_authdata = NULL;
+ krb5_authdata **ext_authdata = NULL, **ap_authdata, **combined;
+ int client_aware_cb;
authent->client = client;
authent->checksum = cksum;
@@ -297,99 +297,104 @@ generate_authenticator(krb5_context context, krb5_authenticator *authent,
krb5_free_authdata(context, ext_authdata);
}
- /* Only send EtypeList if we prefer another enctype to tkt_enctype */
- if (desired_etypes != NULL && desired_etypes[0] != tkt_enctype) {
- TRACE_MK_REQ_ETYPES(context, desired_etypes);
- retval = make_etype_list(context, desired_etypes, tkt_enctype,
- &authent->authorization_data);
+ retval = profile_get_boolean(context->profile, KRB5_CONF_LIBDEFAULTS,
+ KRB5_CONF_CLIENT_AWARE_GSS_BINDINGS, NULL,
+ FALSE, &client_aware_cb);
+ if (retval)
+ return retval;
+
+ /* Add etype negotiation or channel-binding awareness authdata to the
+ * front, if appropriate. */
+ retval = make_ap_authdata(context, desired_etypes, tkt_enctype,
+ client_aware_cb, &ap_authdata);
+ if (retval)
+ return retval;
+ if (ap_authdata != NULL) {
+ retval = krb5_merge_authdata(context, ap_authdata,
+ authent->authorization_data, &combined);
+ krb5_free_authdata(context, ap_authdata);
if (retval)
return retval;
+ krb5_free_authdata(context, authent->authorization_data);
+ authent->authorization_data = combined;
}
return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));
}
-/* RFC 4537 */
+/* Set *out to a DER-encoded RFC 4537 etype list, or to NULL if no etype list
+ * should be sent. */
static krb5_error_code
-make_etype_list(krb5_context context,
- krb5_enctype *desired_etypes,
- krb5_enctype tkt_enctype,
- krb5_authdata ***authdata)
+make_etype_list(krb5_context context, krb5_enctype *desired_enctypes,
+ krb5_enctype tkt_enctype, krb5_data **out)
{
- krb5_error_code code;
- krb5_etype_list etypes;
- krb5_data *enc_etype_list;
- krb5_data *ad_if_relevant;
- krb5_authdata *etype_adata[2], etype_adatum, **adata;
- int i;
+ krb5_etype_list etlist;
+ int count;
- etypes.etypes = desired_etypes;
+ *out = NULL;
- for (etypes.length = 0;
- etypes.etypes[etypes.length] != ENCTYPE_NULL;
- etypes.length++)
- {
- /*
- * RFC 4537:
- *
- * If the enctype of the ticket session key is included in the enctype
- * list sent by the client, it SHOULD be the last on the list;
- */
- if (etypes.length && etypes.etypes[etypes.length - 1] == tkt_enctype)
+ /* Only send a list if we prefer another enctype to tkt_enctype. */
+ if (desired_enctypes == NULL || desired_enctypes[0] == tkt_enctype)
+ return 0;
+
+ /* Count elements of desired_etypes, stopping at tkt_enctypes if present.
+ * (Per RFC 4537, it must be the last option if it is included.) */
+ for (count = 0; desired_enctypes[count] != ENCTYPE_NULL; count++) {
+ if (count > 0 && desired_enctypes[count - 1] == tkt_enctype)
break;
}
- code = encode_krb5_etype_list(&etypes, &enc_etype_list);
- if (code) {
- return code;
- }
-
- etype_adatum.magic = KV5M_AUTHDATA;
- etype_adatum.ad_type = KRB5_AUTHDATA_ETYPE_NEGOTIATION;
- etype_adatum.length = enc_etype_list->length;
- etype_adatum.contents = (krb5_octet *)enc_etype_list->data;
-
- etype_adata[0] = &etype_adatum;
- etype_adata[1] = NULL;
-
- /* Wrap in AD-IF-RELEVANT container */
- code = encode_krb5_authdata(etype_adata, &ad_if_relevant);
- if (code) {
- krb5_free_data(context, enc_etype_list);
- return code;
- }
-
- krb5_free_data(context, enc_etype_list);
-
- adata = *authdata;
- if (adata == NULL) {
- adata = (krb5_authdata **)calloc(2, sizeof(krb5_authdata *));
- i = 0;
- } else {
- for (i = 0; adata[i] != NULL; i++)
- ;
-
- adata = (krb5_authdata **)realloc(*authdata,
- (i + 2) * sizeof(krb5_authdata *));
- }
- if (adata == NULL) {
- krb5_free_data(context, ad_if_relevant);
- return ENOMEM;
- }
- *authdata = adata;
-
- adata[i] = (krb5_authdata *)malloc(sizeof(krb5_authdata));
- if (adata[i] == NULL) {
- krb5_free_data(context, ad_if_relevant);
- return ENOMEM;
- }
- adata[i]->magic = KV5M_AUTHDATA;
- adata[i]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
- adata[i]->length = ad_if_relevant->length;
- adata[i]->contents = (krb5_octet *)ad_if_relevant->data;
- free(ad_if_relevant); /* contents owned by adata[i] */
-
- adata[i + 1] = NULL;
-
- return 0;
+ etlist.etypes = desired_enctypes;
+ etlist.length = count;
+ return encode_krb5_etype_list(&etlist, out);
+}
+
+/* Set *authdata_out to appropriate authenticator authdata for the request,
+ * encoded in a single AD_IF_RELEVANT element. */
+static krb5_error_code
+make_ap_authdata(krb5_context context, krb5_enctype *desired_enctypes,
+ krb5_enctype tkt_enctype, krb5_boolean client_aware_cb,
+ krb5_authdata ***authdata_out)
+{
+ krb5_error_code ret;
+ krb5_authdata etypes_ad, flags_ad, *list[3];
+ krb5_data *der_etypes = NULL;
+ size_t count = 0;
+ uint8_t flagbuf[4];
+ const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
+
+ *authdata_out = NULL;
+
+ /* Include an ETYPE_NEGOTIATION element if appropriate. */
+ ret = make_etype_list(context, desired_enctypes, tkt_enctype, &der_etypes);
+ if (ret)
+ goto cleanup;
+ if (der_etypes != NULL) {
+ etypes_ad.magic = KV5M_AUTHDATA;
+ etypes_ad.ad_type = KRB5_AUTHDATA_ETYPE_NEGOTIATION;
+ etypes_ad.length = der_etypes->length;
+ etypes_ad.contents = (uint8_t *)der_etypes->data;
+ list[count++] = &etypes_ad;
+ }
+
+ /* Include an AP_OPTIONS element if the CBT flag is configured. */
+ if (client_aware_cb != 0) {
+ store_32_le(KERB_AP_OPTIONS_CBT, flagbuf);
+ flags_ad.magic = KV5M_AUTHDATA;
+ flags_ad.ad_type = KRB5_AUTHDATA_AP_OPTIONS;
+ flags_ad.length = 4;
+ flags_ad.contents = flagbuf;
+ list[count++] = &flags_ad;
+ }
+
+ if (count > 0) {
+ list[count] = NULL;
+ ret = krb5_encode_authdata_container(context,
+ KRB5_AUTHDATA_IF_RELEVANT,
+ list, authdata_out);
+ }
+
+cleanup:
+ krb5_free_data(context, der_etypes);
+ return ret;
}

@ -0,0 +1,54 @@
From 9a9ab4b2cad1597cbafbae756483aefa6e36f1eb Mon Sep 17 00:00:00 2001
From: Jiri Sasek <Jiri.Sasek@Oracle.COM>
Date: Fri, 13 Mar 2020 19:02:58 +0100
Subject: [PATCH] Add finalization safety check to com_err
If the linker erroneously runs the libkrb5 finalizer after the
libcom_err finalizer, the consequent remove_error_table() calls could
crash due to accessing a destroyed mutex or an invalid et_list
pointer. Add an unsynchronized check on finalized in
remove_error_table(), and set et_list to null in com_err_terminate()
after destroying the list.
[ghudson@mit.edu: minimized code hanges; rewrote comment and commit
message]
ticket: 8890 (new)
(cherry picked from commit 9d654aa05e26bbf22f140abde3436afeff2fdf8d)
(cherry picked from commit c7a37d3e87132864ebc44710baf1d50a69682b5c)
---
src/util/et/error_message.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/util/et/error_message.c b/src/util/et/error_message.c
index d7069a9df..7dc02a34e 100644
--- a/src/util/et/error_message.c
+++ b/src/util/et/error_message.c
@@ -26,7 +26,7 @@
static struct et_list *et_list;
static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER;
-static int terminated = 0; /* for debugging shlib fini sequence errors */
+static int terminated = 0; /* for safety and finalization debugging */
MAKE_INIT_FUNCTION(com_err_initialize);
MAKE_FINI_FUNCTION(com_err_terminate);
@@ -69,6 +69,7 @@ void com_err_terminate(void)
enext = e->next;
free(e);
}
+ et_list = NULL;
k5_mutex_unlock(&et_list_lock);
k5_mutex_destroy(&et_list_lock);
terminated = 1;
@@ -280,6 +281,10 @@ remove_error_table(const struct error_table *et)
{
struct et_list **ep, *e;
+ /* Safety check in case libraries are finalized in the wrong order. */
+ if (terminated)
+ return ENOENT;
+
if (CALL_INIT_FUNCTION(com_err_initialize))
return 0;
k5_mutex_lock(&et_list_lock);

@ -0,0 +1,97 @@
From 3c47e4adbed5e0a2e7f3993a24097889216a9d50 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sat, 31 Oct 2020 17:07:05 -0400
Subject: [PATCH] Add recursion limit for ASN.1 indefinite lengths
The libkrb5 ASN.1 decoder supports BER indefinite lengths. It
computes the tag length using recursion; the lack of a recursion limit
allows an attacker to overrun the stack and cause the process to
crash. Reported by Demi Obenour.
CVE-2020-28196:
In MIT krb5 releases 1.11 and later, an unauthenticated attacker can
cause a denial of service for any client or server to which it can
send an ASN.1-encoded Kerberos message of sufficient length.
(cherry picked from commit 57415dda6cf04e73ffc3723be518eddfae599bfd)
ticket: 8959
version_fixed: 1.18.3
(cherry picked from commit 207ad69c87cf1b5c047d6c0c0165e5afe29700a6)
---
src/lib/krb5/asn.1/asn1_encode.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/lib/krb5/asn.1/asn1_encode.c b/src/lib/krb5/asn.1/asn1_encode.c
index a160cf4fe..cd6b879f7 100644
--- a/src/lib/krb5/asn.1/asn1_encode.c
+++ b/src/lib/krb5/asn.1/asn1_encode.c
@@ -356,7 +356,7 @@ make_tag(asn1buf *buf, const taginfo *t, size_t len)
static krb5_error_code
get_tag(const uint8_t *asn1, size_t len, taginfo *tag_out,
const uint8_t **contents_out, size_t *clen_out,
- const uint8_t **remainder_out, size_t *rlen_out)
+ const uint8_t **remainder_out, size_t *rlen_out, int recursion)
{
krb5_error_code ret;
uint8_t o;
@@ -394,9 +394,11 @@ get_tag(const uint8_t *asn1, size_t len, taginfo *tag_out,
/* Indefinite form (should not be present in DER, but we accept it). */
if (tag_out->construction != CONSTRUCTED)
return ASN1_MISMATCH_INDEF;
+ if (recursion >= 32)
+ return ASN1_OVERFLOW;
p = asn1;
while (!(len >= 2 && p[0] == 0 && p[1] == 0)) {
- ret = get_tag(p, len, &t, &c, &clen, &p, &len);
+ ret = get_tag(p, len, &t, &c, &clen, &p, &len, recursion + 1);
if (ret)
return ret;
}
@@ -613,7 +615,7 @@ split_der(asn1buf *buf, uint8_t *const *der, size_t len, taginfo *tag_out)
const uint8_t *contents, *remainder;
size_t clen, rlen;
- ret = get_tag(*der, len, tag_out, &contents, &clen, &remainder, &rlen);
+ ret = get_tag(*der, len, tag_out, &contents, &clen, &remainder, &rlen, 0);
if (ret)
return ret;
if (rlen != 0)
@@ -1199,7 +1201,7 @@ decode_atype(const taginfo *t, const uint8_t *asn1, size_t len,
const uint8_t *rem;
size_t rlen;
if (!tag->implicit) {
- ret = get_tag(asn1, len, &inner_tag, &asn1, &len, &rem, &rlen);
+ ret = get_tag(asn1, len, &inner_tag, &asn1, &len, &rem, &rlen, 0);
if (ret)
return ret;
/* Note: we don't check rlen (it should be 0). */
@@ -1420,7 +1422,7 @@ decode_sequence(const uint8_t *asn1, size_t len, const struct seq_info *seq,
for (i = 0; i < seq->n_fields; i++) {
if (len == 0)
break;
- ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len);
+ ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len, 0);
if (ret)
goto error;
/*
@@ -1478,7 +1480,7 @@ decode_sequence_of(const uint8_t *asn1, size_t len,
*seq_out = NULL;
*count_out = 0;
while (len > 0) {
- ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len);
+ ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len, 0);
if (ret)
goto error;
if (!check_atype_tag(elemtype, &t)) {
@@ -1584,7 +1586,7 @@ k5_asn1_full_decode(const krb5_data *code, const struct atype_info *a,
*retrep = NULL;
ret = get_tag((uint8_t *)code->data, code->length, &t, &contents,
- &clen, &remainder, &rlen);
+ &clen, &remainder, &rlen, 0);
if (ret)
return ret;
/* rlen should be 0, but we don't check it (and due to padding in

@ -1,4 +1,4 @@
From d71ebaef4619d6281551793c297caed7a025a909 Mon Sep 17 00:00:00 2001
From 433dd85aaf8d9ed0e923c873f107995232b94422 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Thu, 26 Oct 2023 14:20:34 -0400
Subject: [PATCH] Add request_timeout configuration parameter
@ -16,10 +16,10 @@ ticket: 9106 (new)
4 files changed, 58 insertions(+), 18 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index a33711d918..65fb592d98 100644
index 315253e378..557094f6a2 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -356,6 +356,15 @@ The libdefaults section may contain any of the following relations:
@@ -357,6 +357,15 @@ The libdefaults section may contain any of the following relations:
(:ref:`duration` string.) Sets the default renewable lifetime
for initial ticket requests. The default value is 0.
@ -36,10 +36,10 @@ index a33711d918..65fb592d98 100644
A whitespace or comma-separated list of words which specifies the
groups allowed for SPAKE preauthentication. The possible values
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index b3e07945c1..69d6a6f569 100644
index 912aaedac4..9d5e41ca2c 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -296,6 +296,7 @@ typedef unsigned char u_char;
@@ -293,6 +293,7 @@ typedef unsigned char u_char;
#define KRB5_CONF_SPAKE_PREAUTH_INDICATOR "spake_preauth_indicator"
#define KRB5_CONF_SPAKE_PREAUTH_KDC_CHALLENGE "spake_preauth_kdc_challenge"
#define KRB5_CONF_SPAKE_PREAUTH_GROUPS "spake_preauth_groups"
@ -47,7 +47,7 @@ index b3e07945c1..69d6a6f569 100644
#define KRB5_CONF_TICKET_LIFETIME "ticket_lifetime"
#define KRB5_CONF_UDP_PREFERENCE_LIMIT "udp_preference_limit"
#define KRB5_CONF_UNLOCKITER "unlockiter"
@@ -1200,6 +1201,7 @@ struct _krb5_context {
@@ -1218,6 +1219,7 @@ struct _krb5_context {
kdb5_dal_handle *dal_handle;
/* allowable clock skew */
krb5_deltat clockskew;
@ -56,19 +56,19 @@ index b3e07945c1..69d6a6f569 100644
krb5_flags library_options;
krb5_boolean profile_secure;
diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
index 2b5abcd817..582a2945ff 100644
index 9a4741fa64..1a6e0bf672 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -157,7 +157,7 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
krb5_context ctx = 0;
krb5_error_code retval;
@@ -163,7 +163,7 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
} seed_data;
krb5_data seed;
int tmp;
- char *plugin_dir = NULL;
+ char *plugin_dir = NULL, *timeout_str = NULL;
/* Verify some assumptions. If the assumptions hold and the
compiler is optimizing, this should result in no code being
@@ -240,6 +240,17 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
@@ -257,6 +257,17 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
get_integer(ctx, KRB5_CONF_CLOCKSKEW, DEFAULT_CLOCKSKEW, &tmp);
ctx->clockskew = tmp;
@ -86,7 +86,7 @@ index 2b5abcd817..582a2945ff 100644
get_integer(ctx, KRB5_CONF_KDC_DEFAULT_OPTIONS, KDC_OPT_RENEWABLE_OK,
&tmp);
ctx->kdc_default_options = tmp;
@@ -281,6 +292,7 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
@@ -298,6 +309,7 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
cleanup:
profile_release_string(plugin_dir);
@ -95,10 +95,10 @@ index 2b5abcd817..582a2945ff 100644
return retval;
}
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index 262edf09b4..98247a1089 100644
index 8e4fcd2a38..f57117126e 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -1395,34 +1395,41 @@ get_endtime(time_ms endtime, struct conn_state *conns)
@@ -1390,34 +1390,41 @@ get_endtime(time_ms endtime, struct conn_state *conns)
static krb5_boolean
service_fds(krb5_context context, struct select_state *selstate,
@ -148,7 +148,7 @@ index 262edf09b4..98247a1089 100644
/* Got something on a socket, process it. */
for (state = conns; state != NULL; state = state->next) {
@@ -1495,7 +1502,7 @@ k5_sendto(krb5_context context, const krb5_data *message,
@@ -1490,7 +1497,7 @@ k5_sendto(krb5_context context, const krb5_data *message,
void *msg_handler_data)
{
int pass;
@ -157,7 +157,7 @@ index 262edf09b4..98247a1089 100644
krb5_error_code retval;
struct conn_state *conns = NULL, *state, **tailptr, *next, *winner;
size_t s;
@@ -1505,6 +1512,13 @@ k5_sendto(krb5_context context, const krb5_data *message,
@@ -1500,6 +1507,13 @@ k5_sendto(krb5_context context, const krb5_data *message,
*reply = empty_data();
@ -171,7 +171,7 @@ index 262edf09b4..98247a1089 100644
/* One for use here, listing all our fds in use, and one for
* temporary use in service_fds, for the fds of interest. */
sel_state = malloc(2 * sizeof(*sel_state));
@@ -1532,8 +1546,9 @@ k5_sendto(krb5_context context, const krb5_data *message,
@@ -1527,8 +1541,9 @@ k5_sendto(krb5_context context, const krb5_data *message,
if (maybe_send(context, state, message, sel_state, realm,
callback_info))
continue;
@ -183,7 +183,7 @@ index 262edf09b4..98247a1089 100644
}
}
@@ -1545,13 +1560,13 @@ k5_sendto(krb5_context context, const krb5_data *message,
@@ -1540,13 +1555,13 @@ k5_sendto(krb5_context context, const krb5_data *message,
if (maybe_send(context, state, message, sel_state, realm,
callback_info))
continue;
@ -199,7 +199,7 @@ index 262edf09b4..98247a1089 100644
realm, msg_handler, msg_handler_data, &winner);
}
@@ -1562,15 +1577,17 @@ k5_sendto(krb5_context context, const krb5_data *message,
@@ -1557,15 +1572,17 @@ k5_sendto(krb5_context context, const krb5_data *message,
if (maybe_send(context, state, message, sel_state, realm,
callback_info))
continue;

@ -0,0 +1,303 @@
From bb5552ece2a351dc3ccab52cceea1eaffeacd768 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 14 Dec 2020 13:16:17 -0500
Subject: [PATCH] Add support for start_realm cache config
When making TGS requests, if start_realm is set in the cache, use the
named realm to look up the initial TGT for referral or cross-realm
requests. (Also correct a comment in struct _tkt_creds_context: the
ccache field is an owner pointer, not an alias.)
Add an internal API k5_cc_store_primary_cred(), which sets start_realm
if the cred being stored is a TGT for a realm other than the client
realm. Use this API when acquiring initial tickets with a
caller-specified output ccache, when renewing or validating tickets
with kinit, when accepting a delegated credential in a GSS context,
and when storing a single cred with kvno --out-cache.
ticket: 8332
tags: pullup
target_version: 1.19
(cherry picked from commit 0d56740ab9fcc40dc7f46c6fbebdf8f1214f9d96)
[rharwood@redhat.com: backport around spelling and canonicalization fallback]
---
doc/formats/ccache_file_format.rst | 6 +++++
src/clients/kinit/kinit.c | 2 +-
src/clients/kvno/kvno.c | 5 ++++-
src/include/k5-int.h | 4 ++++
src/lib/gssapi/krb5/accept_sec_context.c | 2 +-
src/lib/krb5/ccache/ccfns.c | 20 +++++++++++++++++
src/lib/krb5/krb/get_creds.c | 28 ++++++++++++++++++------
src/lib/krb5/krb/get_in_tkt.c | 2 +-
src/lib/krb5/libkrb5.exports | 1 +
src/lib/krb5_32.def | 3 +++
src/tests/t_crossrealm.py | 8 +++++++
src/tests/t_pkinit.py | 3 +++
12 files changed, 73 insertions(+), 11 deletions(-)
diff --git a/doc/formats/ccache_file_format.rst b/doc/formats/ccache_file_format.rst
index 6349e0d29..6138c1b58 100644
--- a/doc/formats/ccache_file_format.rst
+++ b/doc/formats/ccache_file_format.rst
@@ -174,3 +174,9 @@ refresh_time
decimal representation of a timestamp at which the GSS mechanism
should attempt to refresh the credential cache from the client
keytab.
+
+start_realm
+ This key indicates the realm of the ticket-granting ticket to be
+ used for TGS requests, when making a referrals request or
+ beginning a cross-realm request. If it is not present, the client
+ realm is used.
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
index 3fdae2878..e5ebeb895 100644
--- a/src/clients/kinit/kinit.c
+++ b/src/clients/kinit/kinit.c
@@ -828,7 +828,7 @@ k5_kinit(struct k_opts *opts, struct k5_data *k5)
if (opts->verbose)
fprintf(stderr, _("Initialized cache\n"));
- ret = krb5_cc_store_cred(k5->ctx, k5->out_cc, &my_creds);
+ ret = k5_cc_store_primary_cred(k5->ctx, k5->out_cc, &my_creds);
if (ret) {
com_err(progname, ret, _("while storing credentials"));
goto cleanup;
diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
index c5f6bf700..f83c68a99 100644
--- a/src/clients/kvno/kvno.c
+++ b/src/clients/kvno/kvno.c
@@ -561,7 +561,10 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
}
initialized = 1;
}
- ret = krb5_cc_store_cred(context, out_ccache, creds);
+ if (count == 1)
+ ret = k5_cc_store_primary_cred(context, out_ccache, creds);
+ else
+ ret = krb5_cc_store_cred(context, out_ccache, creds);
if (ret) {
com_err(prog, ret, _("while storing creds in output ccache"));
exit(1);
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index eb18a4cd6..912aaedac 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -307,6 +307,7 @@ typedef unsigned char u_char;
#define KRB5_CC_CONF_PA_TYPE "pa_type"
#define KRB5_CC_CONF_PROXY_IMPERSONATOR "proxy_impersonator"
#define KRB5_CC_CONF_REFRESH_TIME "refresh_time"
+#define KRB5_CC_CONF_START_REALM "start_realm"
/* Error codes used in KRB_ERROR protocol messages.
Return values of library routines are based on a different error table
@@ -1910,6 +1911,9 @@ krb5_ser_unpack_bytes(krb5_octet *, size_t, krb5_octet **, size_t *);
krb5_error_code KRB5_CALLCONV
krb5int_cc_default(krb5_context, krb5_ccache *);
+krb5_error_code
+k5_cc_store_primary_cred(krb5_context, krb5_ccache, krb5_creds *);
+
/* Fill in the buffer with random alpha-numeric data. */
krb5_error_code
krb5int_random_string(krb5_context, char *string, unsigned int length);
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 3d5b84b15..abccb5d11 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -216,7 +216,7 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
goto cleanup;
- if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
+ if ((retval = k5_cc_store_primary_cred(context, ccache, creds[0])))
goto cleanup;
/* generate a delegated credential handle */
diff --git a/src/lib/krb5/ccache/ccfns.c b/src/lib/krb5/ccache/ccfns.c
index 62a6983d8..23edc2578 100644
--- a/src/lib/krb5/ccache/ccfns.c
+++ b/src/lib/krb5/ccache/ccfns.c
@@ -297,3 +297,23 @@ krb5_cc_switch(krb5_context context, krb5_ccache cache)
return 0;
return cache->ops->switch_to(context, cache);
}
+
+krb5_error_code
+k5_cc_store_primary_cred(krb5_context context, krb5_ccache cache,
+ krb5_creds *creds)
+{
+ krb5_error_code ret;
+
+ /* Write a start realm if we're writing a TGT and the client realm isn't
+ * the same as the TGS realm. */
+ if (IS_TGS_PRINC(creds->server) &&
+ !data_eq(creds->client->realm, creds->server->data[1])) {
+ ret = krb5_cc_set_config(context, cache, NULL,
+ KRB5_CC_CONF_START_REALM,
+ &creds->server->data[1]);
+ if (ret)
+ return ret;
+ }
+
+ return krb5_cc_store_cred(context, cache, creds);
+}
diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c
index e0a3b5cd8..b40f705fc 100644
--- a/src/lib/krb5/krb/get_creds.c
+++ b/src/lib/krb5/krb/get_creds.c
@@ -149,7 +149,8 @@ struct _krb5_tkt_creds_context {
krb5_principal client; /* Caller-requested client principal (alias) */
krb5_principal server; /* Server principal (alias) */
krb5_principal req_server; /* Caller-requested server principal */
- krb5_ccache ccache; /* Caller-provided ccache (alias) */
+ krb5_ccache ccache; /* Caller-provided ccache */
+ krb5_data start_realm; /* Realm of starting TGT in ccache */
krb5_flags req_options; /* Caller-requested KRB5_GC_* options */
krb5_flags req_kdcopt; /* Caller-requested options as KDC options */
krb5_authdata **authdata; /* Caller-requested authdata */
@@ -783,7 +784,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx,
return code;
/* Construct the principal name. */
- code = krb5int_tgtname(context, &ctx->client->realm, &ctx->client->realm,
+ code = krb5int_tgtname(context, &ctx->start_realm, &ctx->start_realm,
&tgtname);
if (code != 0)
return code;
@@ -821,7 +822,7 @@ init_realm_path(krb5_context context, krb5_tkt_creds_context ctx)
size_t nrealms;
/* Get the client realm path and count its length. */
- code = k5_client_realm_path(context, &ctx->client->realm,
+ code = k5_client_realm_path(context, &ctx->start_realm,
&ctx->server->realm, &realm_path);
if (code != 0)
return code;
@@ -933,7 +934,7 @@ step_get_tgt(krb5_context context, krb5_tkt_creds_context ctx)
ctx->cur_realm = path_realm;
ctx->next_realm = ctx->last_realm;
}
- } else if (data_eq(*tgt_realm, ctx->client->realm)) {
+ } else if (data_eq(*tgt_realm, ctx->start_realm)) {
/* We were referred back to the local realm, which is bad. */
return KRB5_KDCREP_MODIFIED;
} else {
@@ -963,7 +964,7 @@ begin_get_tgt(krb5_context context, krb5_tkt_creds_context ctx)
ctx->state = STATE_GET_TGT;
- is_local_service = data_eq(ctx->client->realm, ctx->server->realm);
+ is_local_service = data_eq(ctx->start_realm, ctx->server->realm);
if (!is_local_service) {
/* See if we have a cached TGT for the server realm. */
code = get_cached_tgt(context, ctx, &ctx->server->realm, &cached_tgt);
@@ -1048,10 +1049,10 @@ begin(krb5_context context, krb5_tkt_creds_context ctx)
if (code != 0 || ctx->state == STATE_COMPLETE)
return code;
- /* If the server realm is unspecified, start with the client realm. */
+ /* If the server realm is unspecified, start with the TGT realm. */
if (krb5_is_referral_realm(&ctx->server->realm)) {
krb5_free_data_contents(context, &ctx->server->realm);
- code = krb5int_copy_data_contents(context, &ctx->client->realm,
+ code = krb5int_copy_data_contents(context, &ctx->start_realm,
&ctx->server->realm);
TRACE_TKT_CREDS_REFERRAL_REALM(context, ctx->server);
if (code != 0)
@@ -1100,6 +1101,18 @@ krb5_tkt_creds_init(krb5_context context, krb5_ccache ccache,
code = krb5_cc_dup(context, ccache, &ctx->ccache);
if (code != 0)
goto cleanup;
+
+ /* Get the start realm from the cache config, defaulting to the client
+ * realm. */
+ code = krb5_cc_get_config(context, ccache, NULL, "start_realm",
+ &ctx->start_realm);
+ if (code != 0) {
+ code = krb5int_copy_data_contents(context, &ctx->client->realm,
+ &ctx->start_realm);
+ if (code != 0)
+ goto cleanup;
+ }
+
code = krb5_copy_authdata(context, in_creds->authdata, &ctx->authdata);
if (code != 0)
goto cleanup;
@@ -1139,6 +1152,7 @@ krb5_tkt_creds_free(krb5_context context, krb5_tkt_creds_context ctx)
krb5int_fast_free_state(context, ctx->fast_state);
krb5_free_creds(context, ctx->in_creds);
krb5_cc_close(context, ctx->ccache);
+ krb5_free_data_contents(context, &ctx->start_realm);
krb5_free_principal(context, ctx->req_server);
krb5_free_authdata(context, ctx->authdata);
krb5_free_creds(context, ctx->cur_tgt);
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index cc0f70e83..f5dd7518b 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -1779,7 +1779,7 @@ init_creds_step_reply(krb5_context context,
code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
if (code != 0)
goto cc_cleanup;
- code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
+ code = k5_cc_store_primary_cred(context, out_ccache, &ctx->cred);
if (code != 0)
goto cc_cleanup;
if (fast_avail) {
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 5aba29ee4..cab5b3b17 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -125,6 +125,7 @@ k5_add_pa_data_from_data
k5_alloc_pa_data
k5_authind_decode
k5_build_conf_principals
+k5_cc_store_primary_cred
k5_ccselect_free_context
k5_change_error_message_code
k5_etypes_contains
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
index a0734c729..de5823c17 100644
--- a/src/lib/krb5_32.def
+++ b/src/lib/krb5_32.def
@@ -499,3 +499,6 @@ EXPORTS
k5_size_context @467 ; PRIVATE GSSAPI
k5_size_keyblock @468 ; PRIVATE GSSAPI
k5_size_principal @469 ; PRIVATE GSSAPI
+
+; new in 1.19
+ k5_cc_store_primary_cred @470 ; PRIVATE
diff --git a/src/tests/t_crossrealm.py b/src/tests/t_crossrealm.py
index fa7fd2604..28b397cfb 100755
--- a/src/tests/t_crossrealm.py
+++ b/src/tests/t_crossrealm.py
@@ -77,6 +77,14 @@ r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),
{'realm': 'B.X'}))
test_kvno(r1, r3.host_princ, 'KDC domain walk')
check_klist(r1, (tgt(r1, r1), r3.host_princ))
+
+# Test start_realm in this setup.
+r1.run([kvno, '--out-cache', r1.ccache, r2.krbtgt_princ])
+r1.run([klist, '-C'], expected_msg='config: start_realm = X')
+msgs = ('Requesting TGT krbtgt/B.X@X using TGT krbtgt/X@X',
+ 'Received TGT for service realm: krbtgt/B.X@X')
+r1.run([kvno, r3.host_princ], expected_trace=msgs)
+
stop(r1, r2, r3)
# Test client capaths. The client in A will ask for a cross TGT to D,
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
index ecd450e8a..f224383c8 100755
--- a/src/tests/t_pkinit.py
+++ b/src/tests/t_pkinit.py
@@ -130,6 +130,9 @@ realm.run([kvno, realm.host_princ])
out = realm.run(['./adata', realm.host_princ])
if '97:' in out:
fail('auth indicators seen in anonymous PKINIT ticket')
+# Verify start_realm setting and test referrals TGS request.
+realm.run([klist, '-C'], expected_msg='start_realm = KRBTEST.COM')
+realm.run([kvno, '-S', 'host', hostname])
# Test anonymous kadmin.
mark('anonymous kadmin')

@ -0,0 +1,403 @@
From a1f38973435b60c7f147abfca12b95c6a0a64406 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 17 Jun 2020 20:48:38 -0400
Subject: [PATCH] Add three kvno options from Heimdal kgetcred
Add the flags --cached-only and --no-store, which pass the
corresponding options to krb5_get_credentials(). Add the option
--out-cache to write the retrieved credentials to a specified output
cache.
Add a Python test script for kvno command-line options, including
tests for the new options.
ticket: 8917 (new)
---
doc/user/user_commands/kvno.rst | 13 ++++
src/clients/kvno/Makefile.in | 3 +
src/clients/kvno/kvno.c | 115 +++++++++++++++++++++++---------
src/clients/kvno/t_kvno.py | 75 +++++++++++++++++++++
src/man/kvno.man | 13 ++++
5 files changed, 187 insertions(+), 32 deletions(-)
create mode 100644 src/clients/kvno/t_kvno.py
diff --git a/doc/user/user_commands/kvno.rst b/doc/user/user_commands/kvno.rst
index 3892f0ca5..718313576 100644
--- a/doc/user/user_commands/kvno.rst
+++ b/doc/user/user_commands/kvno.rst
@@ -74,6 +74,19 @@ OPTIONS
client principal with the X.509 certificate in *cert_file*. The
certificate file must be in PEM format.
+**--cached-only**
+ Only retrieve credentials already present in the cache, not from
+ the KDC.
+
+**--no-store**
+ Do not store retrieved credentials in the cache. If
+ **--out-cache** is also specified, credentials will still be
+ stored into the output credential cache.
+
+**--out-cache** *ccache*
+ Initialize *ccache* and store all retrieved credentials into it.
+ Do not store acquired credentials in the input cache.
+
**--u2u** *ccache*
Requests a user-to-user ticket. *ccache* must contain a local
krbtgt ticket for the server principal. The reported version
diff --git a/src/clients/kvno/Makefile.in b/src/clients/kvno/Makefile.in
index 1c3f79392..5ba877271 100644
--- a/src/clients/kvno/Makefile.in
+++ b/src/clients/kvno/Makefile.in
@@ -26,6 +26,9 @@ kvno: kvno.o $(KRB5_BASE_DEPLIBS)
##WIN32## link $(EXE_LINKOPTS) /out:$@ $**
##WIN32## $(_VC_MANIFEST_EMBED_EXE)
+check-pytests: kvno
+ $(RUNPYTEST) $(srcdir)/t_kvno.py $(PYTESTFLAGS)
+
clean-unix::
$(RM) kvno.o kvno
diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
index 2472c0cfe..9d85864f6 100644
--- a/src/clients/kvno/kvno.c
+++ b/src/clients/kvno/kvno.c
@@ -44,14 +44,17 @@ xusage()
fprintf(stderr, _("usage: %s [-C] [-u] [-c ccache] [-e etype]\n"), prog);
fprintf(stderr, _("\t[-k keytab] [-S sname] [{-I | -U} for_user | "
"[-F cert_file] [-P]]\n"));
- fprintf(stderr, _("\t[--u2u ccache] service1 service2 ...\n"));
+ fprintf(stderr, _("\t[--cached-only] [--no-store] [--out-cache ccache] "
+ "[--u2u ccache]\n"));
+ fprintf(stderr, _("\tservice1 service2 ...\n"));
exit(1);
}
static void do_v5_kvno(int argc, char *argv[], char *ccachestr, char *etypestr,
- char *keytab_name, char *sname, int canon, int unknown,
- char *for_user, int for_user_enterprise,
- char *for_user_cert_file, int proxy,
+ char *keytab_name, char *sname, int cached_only,
+ int canon, int no_store, int unknown, char *for_user,
+ int for_user_enterprise, char *for_user_cert_file,
+ int proxy, const char *out_ccname,
const char *u2u_ccname);
#include <com_err.h>
@@ -61,18 +64,21 @@ static void extended_com_err_fn(const char *myprog, errcode_t code,
int
main(int argc, char *argv[])
{
- enum { OPTION_U2U = 256 };
- struct option lopts[] = {
- { "u2u", 1, NULL, OPTION_U2U },
- { NULL, 0, NULL, 0 }
- };
+ enum { OPTION_U2U = 256, OPTION_OUT_CACHE = 257 };
const char *shopts = "uCc:e:hk:qPS:I:U:F:";
int option;
char *etypestr = NULL, *ccachestr = NULL, *keytab_name = NULL;
char *sname = NULL, *for_user = NULL, *u2u_ccname = NULL;
- char *for_user_cert_file = NULL;
+ char *for_user_cert_file = NULL, *out_ccname = NULL;
int canon = 0, unknown = 0, proxy = 0, for_user_enterprise = 0;
- int impersonate = 0;
+ int impersonate = 0, cached_only = 0, no_store = 0;
+ struct option lopts[] = {
+ { "cached-only", 0, &cached_only, 1 },
+ { "no-store", 0, &no_store, 1 },
+ { "out-cache", 1, NULL, OPTION_OUT_CACHE },
+ { "u2u", 1, NULL, OPTION_U2U },
+ { NULL, 0, NULL, 0 }
+ };
setlocale(LC_ALL, "");
set_com_err_hook(extended_com_err_fn);
@@ -135,6 +141,12 @@ main(int argc, char *argv[])
case OPTION_U2U:
u2u_ccname = optarg;
break;
+ case OPTION_OUT_CACHE:
+ out_ccname = optarg;
+ break;
+ case 0:
+ /* If this option set a flag, do nothing else now. */
+ break;
default:
xusage();
break;
@@ -159,8 +171,9 @@ main(int argc, char *argv[])
xusage();
do_v5_kvno(argc - optind, argv + optind, ccachestr, etypestr, keytab_name,
- sname, canon, unknown, for_user, for_user_enterprise,
- for_user_cert_file, proxy, u2u_ccname);
+ sname, cached_only, canon, no_store, unknown, for_user,
+ for_user_enterprise, for_user_cert_file, proxy, out_ccname,
+ u2u_ccname);
return 0;
}
@@ -274,14 +287,16 @@ static krb5_error_code
kvno(const char *name, krb5_ccache ccache, krb5_principal me,
krb5_enctype etype, krb5_keytab keytab, const char *sname,
krb5_flags options, int unknown, krb5_principal for_user_princ,
- krb5_data *for_user_cert, int proxy, krb5_data *u2u_ticket)
+ krb5_data *for_user_cert, int proxy, krb5_data *u2u_ticket,
+ krb5_creds **creds_out)
{
krb5_error_code ret;
krb5_principal server = NULL;
krb5_ticket *ticket = NULL;
- krb5_creds in_creds, *out_creds = NULL;
+ krb5_creds in_creds, *creds = NULL;
char *princ = NULL;
+ *creds_out = NULL;
memset(&in_creds, 0, sizeof(in_creds));
if (sname != NULL) {
@@ -321,13 +336,12 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
in_creds.client = for_user_princ;
in_creds.server = me;
ret = krb5_get_credentials_for_user(context, options, ccache,
- &in_creds, for_user_cert,
- &out_creds);
+ &in_creds, for_user_cert, &creds);
} else {
in_creds.client = me;
in_creds.server = server;
ret = krb5_get_credentials(context, options, ccache, &in_creds,
- &out_creds);
+ &creds);
}
if (ret) {
@@ -336,7 +350,7 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
}
/* We need a native ticket. */
- ret = krb5_decode_ticket(&out_creds->ticket, &ticket);
+ ret = krb5_decode_ticket(&creds->ticket, &ticket);
if (ret) {
com_err(prog, ret, _("while decoding ticket for %s"), princ);
goto cleanup;
@@ -362,15 +376,15 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
}
if (proxy) {
- in_creds.client = out_creds->client;
- out_creds->client = NULL;
- krb5_free_creds(context, out_creds);
- out_creds = NULL;
+ in_creds.client = creds->client;
+ creds->client = NULL;
+ krb5_free_creds(context, creds);
+ creds = NULL;
in_creds.server = server;
ret = krb5_get_credentials_for_proxy(context, KRB5_GC_CANONICALIZE,
ccache, &in_creds, ticket,
- &out_creds);
+ &creds);
krb5_free_principal(context, in_creds.client);
if (ret) {
com_err(prog, ret, _("%s: constrained delegation failed"),
@@ -379,10 +393,13 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
}
}
+ *creds_out = creds;
+ creds = NULL;
+
cleanup:
krb5_free_principal(context, server);
krb5_free_ticket(context, ticket);
- krb5_free_creds(context, out_creds);
+ krb5_free_creds(context, creds);
krb5_free_unparsed_name(context, princ);
return ret;
}
@@ -428,19 +445,28 @@ cleanup:
static void
do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
- char *keytab_name, char *sname, int canon, int unknown,
- char *for_user, int for_user_enterprise,
- char *for_user_cert_file, int proxy, const char *u2u_ccname)
+ char *keytab_name, char *sname, int cached_only, int canon,
+ int no_store, int unknown, char *for_user, int for_user_enterprise,
+ char *for_user_cert_file, int proxy, const char *out_ccname,
+ const char *u2u_ccname)
{
krb5_error_code ret;
- int i, errors, flags;
+ int i, errors, flags, initialized = 0;
krb5_enctype etype;
- krb5_ccache ccache;
+ krb5_ccache ccache, out_ccache = NULL;
krb5_principal me;
krb5_keytab keytab = NULL;
krb5_principal for_user_princ = NULL;
- krb5_flags options = canon ? KRB5_GC_CANONICALIZE : 0;
+ krb5_flags options = 0;
krb5_data cert_data = empty_data(), *user_cert = NULL, *u2u_ticket = NULL;
+ krb5_creds *creds;
+
+ if (canon)
+ options |= KRB5_GC_CANONICALIZE;
+ if (cached_only)
+ options |= KRB5_GC_CACHED;
+ if (no_store || out_ccname != NULL)
+ options |= KRB5_GC_NO_STORE;
ret = krb5_init_context(&context);
if (ret) {
@@ -467,6 +493,14 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
exit(1);
}
+ if (out_ccname != NULL) {
+ ret = krb5_cc_resolve(context, out_ccname, &out_ccache);
+ if (ret) {
+ com_err(prog, ret, _("while resolving output ccache"));
+ exit(1);
+ }
+ }
+
if (keytab_name != NULL) {
ret = krb5_kt_resolve(context, keytab_name, &keytab);
if (ret) {
@@ -513,8 +547,25 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
errors = 0;
for (i = 0; i < count; i++) {
if (kvno(names[i], ccache, me, etype, keytab, sname, options, unknown,
- for_user_princ, user_cert, proxy, u2u_ticket) != 0)
+ for_user_princ, user_cert, proxy, u2u_ticket, &creds) != 0) {
errors++;
+ } else if (out_ccache != NULL) {
+ if (!initialized) {
+ ret = krb5_cc_initialize(context, out_ccache, creds->client);
+ if (ret) {
+ com_err(prog, ret, _("while initializing output ccache"));
+ exit(1);
+ }
+ initialized = 1;
+ }
+ ret = krb5_cc_store_cred(context, out_ccache, creds);
+ if (ret) {
+ com_err(prog, ret, _("while storing creds in output ccache"));
+ exit(1);
+ }
+ }
+
+ krb5_free_creds(context, creds);
}
if (keytab != NULL)
diff --git a/src/clients/kvno/t_kvno.py b/src/clients/kvno/t_kvno.py
new file mode 100644
index 000000000..e98b90e8a
--- /dev/null
+++ b/src/clients/kvno/t_kvno.py
@@ -0,0 +1,75 @@
+from k5test import *
+
+realm = K5Realm()
+
+def check_cache(ccache, expected_services):
+ # Fetch the klist output and skip past the header.
+ lines = realm.run([klist, '-c', ccache]).splitlines()
+ lines = lines[4:]
+
+ # For each line not beginning with an indent, match against the
+ # expected service principals.
+ svcs = {x: True for x in expected_services}
+ for l in lines:
+ if not l.startswith('\t'):
+ svcprinc = l.split()[4]
+ if svcprinc in svcs:
+ del svcs[svcprinc]
+ else:
+ fail('unexpected service princ ' + svcprinc)
+
+ if svcs:
+ fail('services not found in klist output: ' + ' '.join(svcs.keys()))
+
+
+mark('no options')
+realm.run([kvno, realm.user_princ], expected_msg='user@KRBTEST.COM: kvno = 1')
+check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
+
+mark('-e')
+msgs = ('etypes requested in TGS request: camellia128-cts',
+ '/KDC has no support for encryption type')
+realm.run([kvno, '-e', 'camellia128-cts', realm.host_princ],
+ expected_code=1, expected_trace=msgs)
+
+mark('--cached-only')
+realm.run([kvno, '--cached-only', realm.user_princ], expected_msg='kvno = 1')
+realm.run([kvno, '--cached-only', realm.host_princ],
+ expected_code=1, expected_msg='Matching credential not found')
+check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
+
+mark('--no-store')
+realm.run([kvno, '--no-store', realm.host_princ], expected_msg='kvno = 1')
+check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
+
+mark('--out-cache') # and multiple services
+out_ccache = os.path.join(realm.testdir, 'ccache.out')
+realm.run([kvno, '--out-cache', out_ccache,
+ realm.host_princ, realm.admin_princ])
+check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
+check_cache(out_ccache, [realm.host_princ, realm.admin_princ])
+
+mark('--out-cache --cached-only') # tests out-cache overwriting, and -q
+realm.run([kvno, '--out-cache', out_ccache, '--cached-only', realm.host_princ],
+ expected_code=1, expected_msg='Matching credential not found')
+out = realm.run([kvno, '-q', '--out-cache', out_ccache, '--cached-only',
+ realm.user_princ])
+if out:
+ fail('unexpected kvno output with -q')
+check_cache(out_ccache, [realm.user_princ])
+
+mark('-U') # and -c
+svc_ccache = os.path.join(realm.testdir, 'ccache.svc')
+realm.run([kinit, '-k', '-c', svc_ccache, realm.host_princ])
+realm.run([kvno, '-c', svc_ccache, '-U', 'user', realm.host_princ])
+realm.run([klist, '-c', svc_ccache], expected_msg='for client user@')
+realm.run([kvno, '-c', svc_ccache, '-U', 'user', '--out-cache', out_ccache,
+ realm.host_princ])
+out = realm.run([klist, '-c', out_ccache])
+if ('Default principal: user@KRBTEST.COM' not in out):
+ fail('wrong default principal in klist output')
+
+# More S4U options are tested in tests/gssapi/t_s4u.py.
+# --u2u is tested in tests/t_u2u.py.
+
+success('kvno tests')
diff --git a/src/man/kvno.man b/src/man/kvno.man
index 005a2ec97..b9f6739eb 100644
--- a/src/man/kvno.man
+++ b/src/man/kvno.man
@@ -95,6 +95,19 @@ Specifies that protocol transition is to be used, identifying the
client principal with the X.509 certificate in \fIcert_file\fP\&. The
certificate file must be in PEM format.
.TP
+\fB\-\-cached\-only\fP
+Only retrieve credentials already present in the cache, not from
+the KDC.
+.TP
+\fB\-\-no\-store\fP
+Do not store retrieved credentials in the cache. If
+\fB\-\-out\-cache\fP is also specified, credentials will still be
+stored into the output credential cache.
+.TP
+\fB\-\-out\-cache\fP \fIccache\fP
+Initialize \fIccache\fP and store all retrieved credentials into it.
+Do not store acquired credentials in the input cache.
+.TP
\fB\-\-u2u\fP \fIccache\fP
Requests a user\-to\-user ticket. \fIccache\fP must contain a local
krbtgt ticket for the server principal. The reported version

@ -0,0 +1,242 @@
From ab814a990f109357fc4b505169792f9d4d5b5155 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 24 Feb 2020 15:58:59 -0500
Subject: [PATCH] Allow certauth modules to set hw-authent flag
In PKINIT, if a certauth module returns KRB5_CERTAUTH_HWAUTH from its
authorize method, set the hw-authent flag in the ticket.
ticket: 8879 (new)
(cherry picked from commit 50fb43b4a2d97ce2cd53e1ced30e8e8224fede70)
(cherry picked from commit d23b2ed4f06fa77cd021814834dd1391ef6f452f)
---
doc/plugindev/certauth.rst | 7 +++++--
src/include/krb5/certauth_plugin.h | 9 ++++++---
src/lib/krb5/error_tables/k5e1_err.et | 1 +
src/plugins/certauth/test/Makefile.in | 4 ++--
src/plugins/certauth/test/main.c | 11 +++++++++--
src/plugins/preauth/pkinit/pkinit_srv.c | 24 ++++++++++++++++--------
src/tests/t_certauth.py | 13 +++++++++++++
7 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/doc/plugindev/certauth.rst b/doc/plugindev/certauth.rst
index 8a7f7c5eb..3b715f738 100644
--- a/doc/plugindev/certauth.rst
+++ b/doc/plugindev/certauth.rst
@@ -15,8 +15,11 @@ principal. **authorize** receives the DER-encoded certificate, the
requested client principal, and a pointer to the client's
krb5_db_entry (for modules that link against libkdb5). It returns the
authorization status and optionally outputs a list of authentication
-indicator strings to be added to the ticket. A module must use its
-own internal or library-provided ASN.1 certificate decoder.
+indicator strings to be added to the ticket. Beginning in release
+1.19, the authorize method can request that the hardware
+authentication bit be set in the ticket by returning
+**KRB5_CERTAUTH_HWAUTH**. A module must use its own internal or
+library-provided ASN.1 certificate decoder.
A module can optionally create and destroy module data with the
**init** and **fini** methods. Module data objects last for the
diff --git a/src/include/krb5/certauth_plugin.h b/src/include/krb5/certauth_plugin.h
index 3074790f8..3466cf345 100644
--- a/src/include/krb5/certauth_plugin.h
+++ b/src/include/krb5/certauth_plugin.h
@@ -85,14 +85,17 @@ typedef void
(*krb5_certauth_fini_fn)(krb5_context context, krb5_certauth_moddata moddata);
/*
- * Mandatory:
- * Return 0 if the DER-encoded cert is authorized for PKINIT authentication by
- * princ; otherwise return one of the following error codes:
+ * Mandatory: return 0 or KRB5_CERTAUTH_HWAUTH if the DER-encoded cert is
+ * authorized for PKINIT authentication by princ; otherwise return one of the
+ * following error codes:
* - KRB5KDC_ERR_CLIENT_NAME_MISMATCH - incorrect SAN value
* - KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE - incorrect EKU
* - KRB5KDC_ERR_CERTIFICATE_MISMATCH - other extension error
* - KRB5_PLUGIN_NO_HANDLE - the module has no opinion about cert
*
+ * Returning KRB5_CERTAUTH_HWAUTH will cause the hw-authent flag to be set in
+ * the issued ticket (new in release 1.19).
+ *
* - opts is used by built-in modules to receive internal data, and must be
* ignored by other modules.
* - db_entry receives the client principal database entry, and can be ignored
diff --git a/src/lib/krb5/error_tables/k5e1_err.et b/src/lib/krb5/error_tables/k5e1_err.et
index ade5caecf..abd9f3bfe 100644
--- a/src/lib/krb5/error_tables/k5e1_err.et
+++ b/src/lib/krb5/error_tables/k5e1_err.et
@@ -42,4 +42,5 @@ error_code KRB5_KCM_MALFORMED_REPLY, "Malformed reply from KCM daemon"
error_code KRB5_KCM_RPC_ERROR, "Mach RPC error communicating with KCM daemon"
error_code KRB5_KCM_REPLY_TOO_BIG, "KCM daemon reply too big"
error_code KRB5_KCM_NO_SERVER, "No KCM server found"
+error_code KRB5_CERTAUTH_HWAUTH, "Authorize and set hw-authent ticket flag"
end
diff --git a/src/plugins/certauth/test/Makefile.in b/src/plugins/certauth/test/Makefile.in
index d3524084c..e94c13845 100644
--- a/src/plugins/certauth/test/Makefile.in
+++ b/src/plugins/certauth/test/Makefile.in
@@ -5,8 +5,8 @@ LIBBASE=certauth_test
LIBMAJOR=0
LIBMINOR=0
RELDIR=../plugins/certauth/test
-SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS)
-SHLIB_EXPLIBS=$(KRB5_BASE_LIBS)
+SHLIB_EXPDEPS=$(KDB5_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+SHLIB_EXPLIBS=$(KDB5_LIBS) $(KRB5_BASE_LIBS)
STLIBOBJS=main.o
diff --git a/src/plugins/certauth/test/main.c b/src/plugins/certauth/test/main.c
index 77641230c..d4633b8cd 100644
--- a/src/plugins/certauth/test/main.c
+++ b/src/plugins/certauth/test/main.c
@@ -31,6 +31,7 @@
*/
#include <k5-int.h>
+#include <kdb.h>
#include "krb5/certauth_plugin.h"
struct krb5_certauth_moddata_st {
@@ -131,7 +132,8 @@ has_cn(krb5_context context, const uint8_t *cert, size_t cert_len,
/*
* Test module 2 returns OK if princ matches the CN part of the subject name,
- * and returns indicators of the module name and princ.
+ * and returns indicators of the module name and princ. If the "hwauth" string
+ * attribute is set on db_entry, it returns KRB5_CERTAUTH_HWAUTH.
*/
static krb5_error_code
test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
@@ -141,7 +143,7 @@ test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
char ***authinds_out)
{
krb5_error_code ret;
- char *name = NULL, **ais = NULL;
+ char *name = NULL, *strval = NULL, **ais = NULL;
*authinds_out = NULL;
@@ -167,6 +169,11 @@ test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
ais = NULL;
+ ret = krb5_dbe_get_string(context, (krb5_db_entry *)db_entry, "hwauth",
+ &strval);
+ ret = (strval != NULL) ? KRB5_CERTAUTH_HWAUTH : 0;
+ krb5_dbe_free_string(context, strval);
+
cleanup:
krb5_free_unparsed_name(context, name);
return ret;
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index feca11806..3ae56c064 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -320,12 +320,12 @@ static krb5_error_code
authorize_cert(krb5_context context, certauth_handle *certauth_modules,
pkinit_kdc_context plgctx, pkinit_kdc_req_context reqctx,
krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
- krb5_principal client)
+ krb5_principal client, krb5_boolean *hwauth_out)
{
krb5_error_code ret;
certauth_handle h;
struct certauth_req_opts opts;
- krb5_boolean accepted = FALSE;
+ krb5_boolean accepted = FALSE, hwauth = FALSE;
uint8_t *cert;
size_t i, cert_len;
void *db_ent = NULL;
@@ -347,9 +347,10 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
/*
* Check the certificate against each certauth module. For the certificate
- * to be authorized at least one module must return 0, and no module can an
- * error code other than KRB5_PLUGIN_NO_HANDLE (pass). Add indicators from
- * modules that return 0 or pass.
+ * to be authorized at least one module must return 0 or
+ * KRB5_CERTAUTH_HWAUTH, and no module can return an error code other than
+ * KRB5_PLUGIN_NO_HANDLE (pass). Add indicators from modules that return 0
+ * or pass.
*/
ret = KRB5_PLUGIN_NO_HANDLE;
for (i = 0; certauth_modules != NULL && certauth_modules[i] != NULL; i++) {
@@ -359,6 +360,8 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
&opts, db_ent, &ais);
if (ret == 0)
accepted = TRUE;
+ else if (ret == KRB5_CERTAUTH_HWAUTH)
+ accepted = hwauth = TRUE;
else if (ret != KRB5_PLUGIN_NO_HANDLE)
goto cleanup;
@@ -374,6 +377,7 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
}
}
+ *hwauth_out = hwauth;
ret = accepted ? 0 : KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
cleanup:
@@ -430,7 +434,7 @@ pkinit_server_verify_padata(krb5_context context,
int is_signed = 1;
krb5_pa_data **e_data = NULL;
krb5_kdcpreauth_modreq modreq = NULL;
- krb5_boolean valid_freshness_token = FALSE;
+ krb5_boolean valid_freshness_token = FALSE, hwauth = FALSE;
char **sp;
pkiDebug("pkinit_verify_padata: entered!\n");
@@ -494,7 +498,7 @@ pkinit_server_verify_padata(krb5_context context,
}
if (is_signed) {
retval = authorize_cert(context, moddata->certauth_modules, plgctx,
- reqctx, cb, rock, request->client);
+ reqctx, cb, rock, request->client, &hwauth);
if (retval)
goto cleanup;
@@ -613,6 +617,8 @@ pkinit_server_verify_padata(krb5_context context,
/* remember to set the PREAUTH flag in the reply */
enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
+ if (hwauth)
+ enc_tkt_reply->flags |= TKT_FLG_HW_AUTH;
modreq = (krb5_kdcpreauth_modreq)reqctx;
reqctx = NULL;
@@ -1044,7 +1050,9 @@ pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
{
if (patype == KRB5_PADATA_PKINIT_KX)
return PA_INFO;
- return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA;
+ /* PKINIT does not normally set the hw-authent ticket flag, but a
+ * certauth module can cause it to do so. */
+ return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA | PA_HARDWARE;
}
static krb5_preauthtype supported_server_pa_types[] = {
diff --git a/src/tests/t_certauth.py b/src/tests/t_certauth.py
index 9c7094525..0fe0fdb4a 100644
--- a/src/tests/t_certauth.py
+++ b/src/tests/t_certauth.py
@@ -43,4 +43,17 @@ out = realm.kinit("user2@KRBTEST.COM",
expected_code=1,
expected_msg='kinit: Certificate mismatch')
+# Test the KRB5_CERTAUTH_HWAUTH return code.
+mark('hw-authent flag tests')
+# First test +requires_hwauth without causing the hw-authent ticket
+# flag to be set. This currently results in a preauth loop.
+realm.run([kadminl, 'modprinc', '+requires_hwauth', realm.user_princ])
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % file_identity],
+ expected_code=1, expected_msg='Looping detected')
+# Cause the test2 module to return KRB5_CERTAUTH_HWAUTH and try again.
+realm.run([kadminl, 'setstr', realm.user_princ, 'hwauth', 'x'])
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % file_identity])
+
success("certauth tests")

@ -0,0 +1,53 @@
From cbdae9a9dc2a6af5551d26b32c8d473e1e0ce773 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 30 Mar 2020 15:26:02 -0400
Subject: [PATCH] Correctly import "service@" GSS host-based name
The intended way to specify only a service in a GSS host-based name is
to omit the "@" separator. Some applications include the separator
but no hostname, and this happened to yield wildcard hostname behavior
prior to commit 996353767fe8afa7f67a3b5b465e4d70e18bad7c when
shortname qualification was added. To restore this behavior, check in
parse_hostbased() that at least one character is present after the "@"
separator before copying the hostname. Add a test case to t_gssapi.py.
ticket: 8892
tags: pullup
target_version: 1.18-next
(cherry picked from commit a2f047af0400ba8080dc26033fae2b17534501e2)
(cherry picked from commit dd4364d76925ce1fe21c2ab995554d6af3a2ea12)
---
src/lib/gssapi/krb5/import_name.c | 4 ++--
src/tests/gssapi/t_gssapi.py | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
index da2ab1423..21023dd76 100644
--- a/src/lib/gssapi/krb5/import_name.c
+++ b/src/lib/gssapi/krb5/import_name.c
@@ -102,8 +102,8 @@ parse_hostbased(const char *str, size_t len,
memcpy(service, str, servicelen);
service[servicelen] = '\0';
- /* If present, copy the hostname. */
- if (at != NULL) {
+ /* Copy the hostname if present (at least one character after '@'). */
+ if (len - servicelen > 1) {
hostlen = len - servicelen - 1;
host = malloc(hostlen + 1);
if (host == NULL) {
diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
index 54d5cf549..ecf982604 100755
--- a/src/tests/gssapi/t_gssapi.py
+++ b/src/tests/gssapi/t_gssapi.py
@@ -47,6 +47,9 @@ realm.run(['./t_accname', 'p:service2/calvin', 'h:service2'],
expected_msg='service2/calvin')
realm.run(['./t_accname', 'p:service2/calvin', 'h:service1'], expected_code=1,
expected_msg=' found in keytab but does not match server principal')
+# Regression test for #8892 (trailing @ in name).
+realm.run(['./t_accname', 'p:service1/andrew', 'h:service1@'],
+ expected_msg='service1/abraham')
# Test with acceptor name containing service and host. Use the
# client's un-canonicalized hostname as acceptor input to mirror what

@ -0,0 +1,426 @@
From ff6cf2a0545d12a020572dd137fd22d1edc726e4 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 28 Feb 2020 10:11:49 +0100
Subject: [PATCH] Do expiration warnings for all init_creds APIs
Move the password expiration warning code from gic_pwd.c to
get_in_tkt.c. Call it from init_creds_step_reply() on successful
completion.
[ghudson@mit.edu: added test case; simplified doc comment; moved call
site to init_creds_step_reply(); rewrote commit message]
ticket: 8893 (new)
(cherry picked from commit e1efb890f7ac31b32c68ab816ef118dbfb5a8c7e)
(cherry picked from commit c136cfe050d203c910624573a33247fde2889b09)
---
src/include/krb5/krb5.hin | 9 ++-
src/lib/krb5/krb/get_in_tkt.c | 112 ++++++++++++++++++++++++++++++
src/lib/krb5/krb/gic_pwd.c | 110 -----------------------------
src/lib/krb5/krb/t_expire_warn.c | 47 +++++++++----
src/lib/krb5/krb/t_expire_warn.py | 22 ++++--
5 files changed, 165 insertions(+), 135 deletions(-)
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 6355e6540..f8269fb17 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -7174,11 +7174,10 @@ typedef void
*
* Set a callback to receive password and account expiration times.
*
- * This option only applies to krb5_get_init_creds_password(). @a cb will be
- * invoked if and only if credentials are successfully acquired. The callback
- * will receive the @a context from the krb5_get_init_creds_password() call and
- * the @a data argument supplied with this API. The remaining arguments should
- * be interpreted as follows:
+ * @a cb will be invoked if and only if credentials are successfully acquired.
+ * The callback will receive the @a context from the calling function and the
+ * @a data argument supplied with this API. The remaining arguments should be
+ * interpreted as follows:
*
* If @a is_last_req is true, then the KDC reply contained last-req entries
* which unambiguously indicated the password expiration, account expiration,
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index 870df62a1..cc0f70e83 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -1482,6 +1482,116 @@ accept_method_data(krb5_context context, krb5_init_creds_context ctx)
ctx->method_padata);
}
+/* Return the password expiry time indicated by enc_part2. Set *is_last_req
+ * if the information came from a last_req value. */
+static void
+get_expiry_times(krb5_enc_kdc_rep_part *enc_part2, krb5_timestamp *pw_exp,
+ krb5_timestamp *acct_exp, krb5_boolean *is_last_req)
+{
+ krb5_last_req_entry **last_req;
+ krb5_int32 lr_type;
+
+ *pw_exp = 0;
+ *acct_exp = 0;
+ *is_last_req = FALSE;
+
+ /* Look for last-req entries for password or account expiration. */
+ if (enc_part2->last_req) {
+ for (last_req = enc_part2->last_req; *last_req; last_req++) {
+ lr_type = (*last_req)->lr_type;
+ if (lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
+ lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
+ *is_last_req = TRUE;
+ *pw_exp = (*last_req)->value;
+ } else if (lr_type == KRB5_LRQ_ALL_ACCT_EXPTIME ||
+ lr_type == KRB5_LRQ_ONE_ACCT_EXPTIME) {
+ *is_last_req = TRUE;
+ *acct_exp = (*last_req)->value;
+ }
+ }
+ }
+
+ /* If we didn't find any, use the ambiguous key_exp field. */
+ if (*is_last_req == FALSE)
+ *pw_exp = enc_part2->key_exp;
+}
+
+/*
+ * Send an appropriate warning prompter if as_reply indicates that the password
+ * is going to expire soon. If an expire callback was provided, use that
+ * instead.
+ */
+static void
+warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
+ krb5_prompter_fct prompter, void *data,
+ const char *in_tkt_service, krb5_kdc_rep *as_reply)
+{
+ krb5_error_code ret;
+ krb5_expire_callback_func expire_cb;
+ void *expire_data;
+ krb5_timestamp pw_exp, acct_exp, now;
+ krb5_boolean is_last_req;
+ krb5_deltat delta;
+ char ts[256], banner[1024];
+
+ if (as_reply == NULL || as_reply->enc_part2 == NULL)
+ return;
+
+ get_expiry_times(as_reply->enc_part2, &pw_exp, &acct_exp, &is_last_req);
+
+ k5_gic_opt_get_expire_cb(options, &expire_cb, &expire_data);
+ if (expire_cb != NULL) {
+ /* Invoke the expire callback and don't send prompter warnings. */
+ (*expire_cb)(context, expire_data, pw_exp, acct_exp, is_last_req);
+ return;
+ }
+
+ /* Don't warn if no password expiry value was sent. */
+ if (pw_exp == 0)
+ return;
+
+ /* Don't warn if the password is being changed. */
+ if (in_tkt_service && strcmp(in_tkt_service, "kadmin/changepw") == 0)
+ return;
+
+ /*
+ * If the expiry time came from a last_req field, assume the KDC wants us
+ * to warn. Otherwise, warn only if the expiry time is less than a week
+ * from now.
+ */
+ ret = krb5_timeofday(context, &now);
+ if (ret != 0)
+ return;
+ if (!is_last_req &&
+ (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60))
+ return;
+
+ if (!prompter)
+ return;
+
+ ret = krb5_timestamp_to_string(pw_exp, ts, sizeof(ts));
+ if (ret != 0)
+ return;
+
+ delta = ts_delta(pw_exp, now);
+ if (delta < 3600) {
+ snprintf(banner, sizeof(banner),
+ _("Warning: Your password will expire in less than one hour "
+ "on %s"), ts);
+ } else if (delta < 86400 * 2) {
+ snprintf(banner, sizeof(banner),
+ _("Warning: Your password will expire in %d hour%s on %s"),
+ delta / 3600, delta < 7200 ? "" : "s", ts);
+ } else {
+ snprintf(banner, sizeof(banner),
+ _("Warning: Your password will expire in %d days on %s"),
+ delta / 86400, ts);
+ }
+
+ /* PROMPTER_INVOCATION */
+ (*prompter)(context, data, 0, banner, 0, 0);
+}
+
static krb5_error_code
init_creds_step_reply(krb5_context context,
krb5_init_creds_context ctx,
@@ -1693,6 +1803,8 @@ init_creds_step_reply(krb5_context context,
/* success */
ctx->complete = TRUE;
+ warn_pw_expiry(context, ctx->opt, ctx->prompter, ctx->prompter_data,
+ ctx->in_tkt_service, ctx->reply);
cleanup:
krb5_free_pa_data(context, kdc_padata);
diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c
index 14ce23ba4..54e0a8ebe 100644
--- a/src/lib/krb5/krb/gic_pwd.c
+++ b/src/lib/krb5/krb/gic_pwd.c
@@ -133,113 +133,6 @@ krb5_init_creds_set_password(krb5_context context,
return 0;
}
-/* Return the password expiry time indicated by enc_part2. Set *is_last_req
- * if the information came from a last_req value. */
-static void
-get_expiry_times(krb5_enc_kdc_rep_part *enc_part2, krb5_timestamp *pw_exp,
- krb5_timestamp *acct_exp, krb5_boolean *is_last_req)
-{
- krb5_last_req_entry **last_req;
- krb5_int32 lr_type;
-
- *pw_exp = 0;
- *acct_exp = 0;
- *is_last_req = FALSE;
-
- /* Look for last-req entries for password or account expiration. */
- if (enc_part2->last_req) {
- for (last_req = enc_part2->last_req; *last_req; last_req++) {
- lr_type = (*last_req)->lr_type;
- if (lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
- lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
- *is_last_req = TRUE;
- *pw_exp = (*last_req)->value;
- } else if (lr_type == KRB5_LRQ_ALL_ACCT_EXPTIME ||
- lr_type == KRB5_LRQ_ONE_ACCT_EXPTIME) {
- *is_last_req = TRUE;
- *acct_exp = (*last_req)->value;
- }
- }
- }
-
- /* If we didn't find any, use the ambiguous key_exp field. */
- if (*is_last_req == FALSE)
- *pw_exp = enc_part2->key_exp;
-}
-
-/*
- * Send an appropriate warning prompter if as_reply indicates that the password
- * is going to expire soon. If an expire callback was provided, use that
- * instead.
- */
-static void
-warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
- krb5_prompter_fct prompter, void *data,
- const char *in_tkt_service, krb5_kdc_rep *as_reply)
-{
- krb5_error_code ret;
- krb5_expire_callback_func expire_cb;
- void *expire_data;
- krb5_timestamp pw_exp, acct_exp, now;
- krb5_boolean is_last_req;
- krb5_deltat delta;
- char ts[256], banner[1024];
-
- get_expiry_times(as_reply->enc_part2, &pw_exp, &acct_exp, &is_last_req);
-
- k5_gic_opt_get_expire_cb(options, &expire_cb, &expire_data);
- if (expire_cb != NULL) {
- /* Invoke the expire callback and don't send prompter warnings. */
- (*expire_cb)(context, expire_data, pw_exp, acct_exp, is_last_req);
- return;
- }
-
- /* Don't warn if no password expiry value was sent. */
- if (pw_exp == 0)
- return;
-
- /* Don't warn if the password is being changed. */
- if (in_tkt_service && strcmp(in_tkt_service, "kadmin/changepw") == 0)
- return;
-
- /*
- * If the expiry time came from a last_req field, assume the KDC wants us
- * to warn. Otherwise, warn only if the expiry time is less than a week
- * from now.
- */
- ret = krb5_timeofday(context, &now);
- if (ret != 0)
- return;
- if (!is_last_req &&
- (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60))
- return;
-
- if (!prompter)
- return;
-
- ret = krb5_timestamp_to_string(pw_exp, ts, sizeof(ts));
- if (ret != 0)
- return;
-
- delta = ts_delta(pw_exp, now);
- if (delta < 3600) {
- snprintf(banner, sizeof(banner),
- _("Warning: Your password will expire in less than one hour "
- "on %s"), ts);
- } else if (delta < 86400*2) {
- snprintf(banner, sizeof(banner),
- _("Warning: Your password will expire in %d hour%s on %s"),
- delta / 3600, delta < 7200 ? "" : "s", ts);
- } else {
- snprintf(banner, sizeof(banner),
- _("Warning: Your password will expire in %d days on %s"),
- delta / 86400, ts);
- }
-
- /* PROMPTER_INVOCATION */
- (*prompter)(context, data, 0, banner, 0, 0);
-}
-
/*
* Create a temporary options structure for getting a kadmin/changepw ticket,
* based on the appplication-specified options. Propagate all application
@@ -496,9 +389,6 @@ krb5_get_init_creds_password(krb5_context context,
goto cleanup;
cleanup:
- if (ret == 0)
- warn_pw_expiry(context, options, prompter, data, in_tkt_service,
- as_reply);
free(chpw_opts);
zapfree(gakpw.storage.data, gakpw.storage.length);
memset(pw0array, 0, sizeof(pw0array));
diff --git a/src/lib/krb5/krb/t_expire_warn.c b/src/lib/krb5/krb/t_expire_warn.c
index 1e59acba1..dc8dc8fb3 100644
--- a/src/lib/krb5/krb/t_expire_warn.c
+++ b/src/lib/krb5/krb/t_expire_warn.c
@@ -28,6 +28,13 @@
static int exp_dummy, prompt_dummy;
+static void
+check(krb5_error_code code)
+{
+ if (code != 0)
+ abort();
+}
+
static krb5_error_code
prompter_cb(krb5_context ctx, void *data, const char *name,
const char *banner, int num_prompts, krb5_prompt prompts[])
@@ -52,36 +59,48 @@ int
main(int argc, char **argv)
{
krb5_context ctx;
+ krb5_init_creds_context icctx;
krb5_get_init_creds_opt *opt;
char *user, *password, *service = NULL;
- krb5_boolean use_cb;
+ krb5_boolean use_cb, stepwise;
krb5_principal client;
krb5_creds creds;
- if (argc < 4) {
- fprintf(stderr, "Usage: %s username password {1|0} [service]\n",
+ if (argc < 5) {
+ fprintf(stderr, "Usage: %s username password {1|0} {1|0} [service]\n",
argv[0]);
return 1;
}
user = argv[1];
password = argv[2];
use_cb = atoi(argv[3]);
- if (argc >= 5)
- service = argv[4];
+ stepwise = atoi(argv[4]);
+ if (argc >= 6)
+ service = argv[5];
- assert(krb5_init_context(&ctx) == 0);
- assert(krb5_get_init_creds_opt_alloc(ctx, &opt) == 0);
+ check(krb5_init_context(&ctx));
+ check(krb5_get_init_creds_opt_alloc(ctx, &opt));
if (use_cb) {
- assert(krb5_get_init_creds_opt_set_expire_callback(ctx, opt, expire_cb,
- &exp_dummy) == 0);
+ check(krb5_get_init_creds_opt_set_expire_callback(ctx, opt, expire_cb,
+ &exp_dummy));
+ }
+ check(krb5_parse_name(ctx, user, &client));
+ if (stepwise) {
+ check(krb5_init_creds_init(ctx, client, prompter_cb, &prompt_dummy, 0,
+ opt, &icctx));
+ krb5_init_creds_set_password(ctx, icctx, password);
+ if (service != NULL)
+ check(krb5_init_creds_set_service(ctx, icctx, service));
+ check(krb5_init_creds_get(ctx, icctx));
+ krb5_init_creds_free(ctx, icctx);
+ } else {
+ check(krb5_get_init_creds_password(ctx, &creds, client, password,
+ prompter_cb, &prompt_dummy, 0,
+ service, opt));
+ krb5_free_cred_contents(ctx, &creds);
}
- assert(krb5_parse_name(ctx, user, &client) == 0);
- assert(krb5_get_init_creds_password(ctx, &creds, client, password,
- prompter_cb, &prompt_dummy, 0, service,
- opt) == 0);
krb5_get_init_creds_opt_free(ctx, opt);
krb5_free_principal(ctx, client);
- krb5_free_cred_contents(ctx, &creds);
krb5_free_context(ctx);
return 0;
}
diff --git a/src/lib/krb5/krb/t_expire_warn.py b/src/lib/krb5/krb/t_expire_warn.py
index 781f2728a..e163cc7e4 100755
--- a/src/lib/krb5/krb/t_expire_warn.py
+++ b/src/lib/krb5/krb/t_expire_warn.py
@@ -34,23 +34,33 @@ realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '12 hours',
realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '3 days', 'days'])
# Check for expected prompter warnings when no expire callback is used.
-output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0'])
+output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0', '0'])
if output:
fail('Unexpected output for noexpire')
-realm.run(['./t_expire_warn', 'minutes', 'pass', '0'],
+realm.run(['./t_expire_warn', 'minutes', 'pass', '0', '0'],
expected_msg=' less than one hour on ')
-realm.run(['./t_expire_warn', 'hours', 'pass', '0'], expected_msg=' hours on ')
-realm.run(['./t_expire_warn', 'days', 'pass', '0'], expected_msg=' days on ')
+realm.run(['./t_expire_warn', 'hours', 'pass', '0', '0'],
+ expected_msg=' hours on ')
+realm.run(['./t_expire_warn', 'days', 'pass', '0', '0'],
+ expected_msg=' days on ')
+# Try one case with the stepwise interface.
+realm.run(['./t_expire_warn', 'days', 'pass', '0', '1'],
+ expected_msg=' days on ')
# Check for expected expire callback behavior. These tests are
# carefully agnostic about whether the KDC supports last_req fields,
# and could be made more specific if last_req support is added.
-output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '1'])
+output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '1', '0'])
if 'password_expiration = 0\n' not in output or \
'account_expiration = 0\n' not in output or \
'is_last_req = ' not in output:
fail('Expected callback output not seen for noexpire')
-output = realm.run(['./t_expire_warn', 'days', 'pass', '1'])
+output = realm.run(['./t_expire_warn', 'days', 'pass', '1', '0'])
+if 'password_expiration = ' not in output or \
+ 'password_expiration = 0\n' in output:
+ fail('Expected non-zero password expiration not seen for days')
+# Try one case with the stepwise interface.
+output = realm.run(['./t_expire_warn', 'days', 'pass', '1', '1'])
if 'password_expiration = ' not in output or \
'password_expiration = 0\n' in output:
fail('Expected non-zero password expiration not seen for days')

@ -0,0 +1,39 @@
From 5c1c391a80edd8ceb9e8bba9f7bdfb6639883ae6 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 24 Nov 2020 12:52:02 -0500
Subject: [PATCH] Document -k option in kvno(1) synopsis
becd1ad6830b526d08ddaf5b2b6f213154c6446c attempted to unify the
synopsis, option descriptions, and xusage(), but missed one option.
(cherry picked from commit d81e76d9ddab9e880bcf54eabf07119af91d28c7)
(cherry picked from commit 588d964f59356373353dfd31d4fdcba95e508385)
---
doc/user/user_commands/kvno.rst | 1 +
src/man/kvno.man | 1 +
2 files changed, 2 insertions(+)
diff --git a/doc/user/user_commands/kvno.rst b/doc/user/user_commands/kvno.rst
index 65c44e1c0..93a5132b2 100644
--- a/doc/user/user_commands/kvno.rst
+++ b/doc/user/user_commands/kvno.rst
@@ -9,6 +9,7 @@ SYNOPSIS
**kvno**
[**-c** *ccache*]
[**-e** *etype*]
+[**-k** *keytab*]
[**-q**]
[**-u** | **-S** *sname*]
[**-P**]
diff --git a/src/man/kvno.man b/src/man/kvno.man
index 22318324d..4e5b43b3b 100644
--- a/src/man/kvno.man
+++ b/src/man/kvno.man
@@ -35,6 +35,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
\fBkvno\fP
[\fB\-c\fP \fIccache\fP]
[\fB\-e\fP \fIetype\fP]
+[\fB\-k\fP \fIkeytab\fP]
[\fB\-q\fP]
[\fB\-u\fP | \fB\-S\fP \fIsname\fP]
[\fB\-P\fP]

@ -0,0 +1,94 @@
From e2cc7a04f0dbfbf1a8bc6cd70f639c56a203af28 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 23 Mar 2020 19:10:03 -0400
Subject: [PATCH] Eliminate redundant PKINIT responder invocation
In pkinit_client_prep_questions(), only act if the input padata type
is KRB5_PADATA_PK_AS_REQ. Otherwise we will ask questions again when
the KDC issues a ticket.
Commit 7621d2f9a87214327ca3b2594e34dc7cea84596b (ticket 8242)
unintentionally changed the behavior of pkinit_load_fs_cert_and_key(),
causing pkinit_client_prep_questions() to do nothing on its first
call. Restore the original behavior of returning 0 when prompting is
deferred.
Modify the existing "FILE identity, password on key (responder)"
PKINIT test to check that the responder is only invoked once.
ticket: 8885
(cherry picked from commit f1286842ce7b9e507a4ce0a47f44ab361a98be63)
(cherry picked from commit 4a05805eb39ba088c07f782fb52a6538ec3f2db6)
---
src/plugins/preauth/pkinit/pkinit_clnt.c | 5 +++++
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 13 +++++++------
src/tests/t_pkinit.py | 11 +++++++----
3 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index 2f0431991..9b991ffe0 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -897,6 +897,11 @@ pkinit_client_prep_questions(krb5_context context,
k5_json_object jval = NULL;
k5_json_number jflag = NULL;
+ /* Don't ask questions for the informational padata items or when the
+ * ticket is issued. */
+ if (pa_data->pa_type != KRB5_PADATA_PK_AS_REQ)
+ return 0;
+
if (!reqctx->identity_initialized) {
pkinit_client_profile(context, plgctx, reqctx, cb, rock,
&request->server->realm);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index dd718c2be..dbb054378 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -4362,17 +4362,18 @@ pkinit_load_fs_cert_and_key(krb5_context context,
/* Load the certificate. */
retval = get_cert(certname, &x);
- if (retval != 0 || x == NULL) {
- retval = oerr(context, 0, _("Cannot read certificate file '%s'"),
+ if (retval) {
+ retval = oerr(context, retval, _("Cannot read certificate file '%s'"),
certname);
- goto cleanup;
}
+ if (retval || x == NULL)
+ goto cleanup;
/* Load the key. */
retval = get_key(context, id_cryptoctx, keyname, fsname, &y, password);
- if (retval != 0 || y == NULL) {
- retval = oerr(context, 0, _("Cannot read key file '%s'"), fsname);
+ if (retval)
+ retval = oerr(context, retval, _("Cannot read key file '%s'"), fsname);
+ if (retval || y == NULL)
goto cleanup;
- }
id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
if (id_cryptoctx->creds[cindex] == NULL) {
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
index 69daf4987..ecd450e8a 100755
--- a/src/tests/t_pkinit.py
+++ b/src/tests/t_pkinit.py
@@ -248,10 +248,13 @@ realm.run(['./adata', realm.host_princ],
# supplied by the responder.
# Supply the response in raw form.
mark('FILE identity, password on key (responder)')
-realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity,
- '-r', 'pkinit={"%s": "encrypted"}' % file_enc_identity,
- '-X', 'X509_user_identity=%s' % file_enc_identity,
- realm.user_princ])
+out = realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity,
+ '-r', 'pkinit={"%s": "encrypted"}' % file_enc_identity,
+ '-X', 'X509_user_identity=%s' % file_enc_identity,
+ realm.user_princ])
+# Regression test for #8885 (password question asked twice).
+if out.count('OK: ') != 1:
+ fail('Wrong number of responder calls')
# Supply the response through the convenience API.
realm.run(['./responder', '-X', 'X509_user_identity=%s' % file_enc_identity,
'-p', '%s=%s' % (file_enc_identity, 'encrypted'), realm.user_princ])

@ -1,4 +1,4 @@
From 347079e258e6ded99d8dda162cafaf133b982ab9 Mon Sep 17 00:00:00 2001
From a68fba22588cc21dcd1dc28550529187dca58331 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 27 Oct 2023 00:44:53 -0400
Subject: [PATCH] End connection on KDC_ERR_SVC_UNAVAILABLE
@ -14,10 +14,10 @@ ticket: 7899
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index 0f4bf23a95..262edf09b4 100644
index d76e24ccf0..8e4fcd2a38 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -1440,7 +1440,10 @@ service_fds(krb5_context context, struct select_state *selstate,
@@ -1435,7 +1435,10 @@ service_fds(krb5_context context, struct select_state *selstate,
if (msg_handler != NULL) {
krb5_data reply = make_data(state->in.buf, state->in.pos);

@ -0,0 +1,258 @@
From b0372e31b81321a820204450a35c7633caf1b7dd Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 14 Jan 2022 02:05:58 -0500
Subject: [PATCH] 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,105 @@
From 261b0ed68fb83c34c70679ae8452cae2dba7e4e3 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 29 Mar 2021 14:32:56 -0400
Subject: [PATCH] Fix KCM flag transmission for remove_cred
MIT krb5 uses low bits for KRB5_TC flags, while Heimdal uses high bits
so that the same flag word can also hold KRB5_GC flags. Add a mapping
function and send the Heimdal flag values when performing a
remove_cred operation.
ticket: 8995
(cherry picked from commit 11a82cf424f9c905bb73680c64524f087090d4ef)
(cherry picked from commit 04f0de4420508161ce439f262f2761ff51a07ab0)
(cherry picked from commit ddbb295dee2adcc6cec26944974420bba188f191)
---
src/include/kcm.h | 19 +++++++++++++++++++
src/lib/krb5/ccache/cc_kcm.c | 36 +++++++++++++++++++++++++++++++++++-
2 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/src/include/kcm.h b/src/include/kcm.h
index e4140c3a0..9b66f1cbd 100644
--- a/src/include/kcm.h
+++ b/src/include/kcm.h
@@ -56,8 +56,27 @@
* are marshalled as zero-terminated strings. Principals and credentials are
* marshalled in the v4 FILE ccache format. UUIDs are 16 bytes. UUID lists
* are not delimited, so nothing can come after them.
+ *
+ * Flag words must use Heimdal flag values, which are not the same as MIT krb5
+ * values for KRB5_GC and KRB5_TC constants. The same flag word may contain
+ * both kinds of flags in Heimdal, but not in MIT krb5. Defines for the
+ * applicable Heimdal flag values are given below using KCM_GC and KCM_TC
+ * prefixes.
*/
+#define KCM_GC_CACHED (1U << 0)
+
+#define KCM_TC_DONT_MATCH_REALM (1U << 31)
+#define KCM_TC_MATCH_KEYTYPE (1U << 30)
+#define KCM_TC_MATCH_SRV_NAMEONLY (1U << 29)
+#define KCM_TC_MATCH_FLAGS_EXACT (1U << 28)
+#define KCM_TC_MATCH_FLAGS (1U << 27)
+#define KCM_TC_MATCH_TIMES_EXACT (1U << 26)
+#define KCM_TC_MATCH_TIMES (1U << 25)
+#define KCM_TC_MATCH_AUTHDATA (1U << 24)
+#define KCM_TC_MATCH_2ND_TKT (1U << 23)
+#define KCM_TC_MATCH_IS_SKEY (1U << 22)
+
/* Opcodes without comments are currently unused in the MIT client
* implementation. */
typedef enum kcm_opcode {
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
index 197a10fba..4141140c3 100644
--- a/src/lib/krb5/ccache/cc_kcm.c
+++ b/src/lib/krb5/ccache/cc_kcm.c
@@ -110,6 +110,40 @@ map_invalid(krb5_error_code code)
KRB5_KCM_MALFORMED_REPLY : code;
}
+/*
+ * Map an MIT krb5 KRB5_TC flag word to the equivalent Heimdal flag word. Note
+ * that there is no MIT krb5 equivalent for Heimdal's KRB5_TC_DONT_MATCH_REALM
+ * (which is like KRB5_TC_MATCH_SRV_NAMEONLY but also applies to the client
+ * principal) and no Heimdal equivalent for MIT krb5's KRB5_TC_SUPPORTED_KTYPES
+ * (which matches against enctypes from the krb5_context rather than the
+ * matching cred).
+ */
+static inline krb5_flags
+map_tcflags(krb5_flags mitflags)
+{
+ krb5_flags heimflags = 0;
+
+ if (mitflags & KRB5_TC_MATCH_TIMES)
+ heimflags |= KCM_TC_MATCH_TIMES;
+ if (mitflags & KRB5_TC_MATCH_IS_SKEY)
+ heimflags |= KCM_TC_MATCH_IS_SKEY;
+ if (mitflags & KRB5_TC_MATCH_FLAGS)
+ heimflags |= KCM_TC_MATCH_FLAGS;
+ if (mitflags & KRB5_TC_MATCH_TIMES_EXACT)
+ heimflags |= KCM_TC_MATCH_TIMES_EXACT;
+ if (mitflags & KRB5_TC_MATCH_FLAGS_EXACT)
+ heimflags |= KCM_TC_MATCH_FLAGS_EXACT;
+ if (mitflags & KRB5_TC_MATCH_AUTHDATA)
+ heimflags |= KCM_TC_MATCH_AUTHDATA;
+ if (mitflags & KRB5_TC_MATCH_SRV_NAMEONLY)
+ heimflags |= KCM_TC_MATCH_SRV_NAMEONLY;
+ if (mitflags & KRB5_TC_MATCH_2ND_TKT)
+ heimflags |= KCM_TC_MATCH_2ND_TKT;
+ if (mitflags & KRB5_TC_MATCH_KTYPE)
+ heimflags |= KCM_TC_MATCH_KEYTYPE;
+ return heimflags;
+}
+
/* Begin a request for the given opcode. If cache is non-null, supply the
* cache name as a request parameter. */
static void
@@ -936,7 +970,7 @@ kcm_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags,
struct kcmreq req;
kcmreq_init(&req, KCM_OP_REMOVE_CRED, cache);
- k5_buf_add_uint32_be(&req.reqbuf, flags);
+ k5_buf_add_uint32_be(&req.reqbuf, map_tcflags(flags));
k5_marshal_mcred(&req.reqbuf, mcred);
ret = cache_call(context, cache, &req);
kcmreq_free(&req);

@ -0,0 +1,64 @@
From 0bfe0b2bc0a8ee0e9a8cee26528030c16d4fd15f Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 11 May 2021 14:04:07 -0400
Subject: [PATCH] Fix KCM retrieval support for sssd
Commit 795ebba8c039be172ab93cd41105c73ffdba0fdb added a retrieval
handler using KCM_OP_RETRIEVE, falling back on the same error codes as
the previous KCM_OP_GET_CRED_LIST support. But sssd (as of 2.4)
returns KRB5_CC_NOSUPP instead of KRB5_CC_IO if it recognizes an
opcode but does not implement it. Add a helper function to recognize
all known unsupported-opcode error codes, and use it in kcm_retrieve()
and kcm_start_seq_get().
ticket: 8997
(cherry picked from commit da103e36e13f3c846bcddbe38dd518a21e5260a0)
(cherry picked from commit a5b2cff51808cd86fe8195e7ac074ecd25c3344d)
(cherry picked from commit 6a00fd149edd017ece894566771e2e9d4ba089f4)
---
src/lib/krb5/ccache/cc_kcm.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
index b600c6f15..6a36cfdce 100644
--- a/src/lib/krb5/ccache/cc_kcm.c
+++ b/src/lib/krb5/ccache/cc_kcm.c
@@ -144,6 +144,20 @@ map_tcflags(krb5_flags mitflags)
return heimflags;
}
+/*
+ * Return true if code could indicate an unsupported operation. Heimdal's KCM
+ * returns KRB5_FCC_INTERNAL. sssd's KCM daemon (as of sssd 2.4) returns
+ * KRB5_CC_NO_SUPP if it recognizes the operation but does not implement it,
+ * and KRB5_CC_IO if it doesn't recognize the operation (which is unfortunate
+ * since it could also indicate a communication failure).
+ */
+static krb5_boolean
+unsupported_op_error(krb5_error_code code)
+{
+ return code == KRB5_FCC_INTERNAL || code == KRB5_CC_IO ||
+ code == KRB5_CC_NOSUPP;
+}
+
/* Begin a request for the given opcode. If cache is non-null, supply the
* cache name as a request parameter. */
static void
@@ -841,7 +855,7 @@ kcm_retrieve(krb5_context context, krb5_ccache cache, krb5_flags flags,
ret = cache_call(context, cache, &req);
/* Fall back to iteration if the server does not support retrieval. */
- if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
+ if (unsupported_op_error(ret)) {
ret = k5_cc_retrieve_cred_default(context, cache, flags, mcred,
cred_out);
goto cleanup;
@@ -922,7 +936,7 @@ kcm_start_seq_get(krb5_context context, krb5_ccache cache,
ret = kcmreq_get_cred_list(&req, &creds);
if (ret)
goto cleanup;
- } else if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
+ } else if (unsupported_op_error(ret)) {
/* Fall back to GET_CRED_UUID_LIST. */
kcmreq_free(&req);
kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);

@ -0,0 +1,47 @@
From 0a8dfc380fe3b210662ba1b1d452fcec2f84841b Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 3 Aug 2021 01:15:27 -0400
Subject: [PATCH] Fix KDC null deref on TGS inner body null server
After the KDC decodes a FAST inner body, it does not check for a null
server. Prior to commit 39548a5b17bbda9eeb63625a201cfd19b9de1c5b this
would typically result in an error from krb5_unparse_name(), but with
the addition of get_local_tgt() it results in a null dereference. Add
a null check.
Reported by Joseph Sutton of Catalyst.
CVE-2021-37750:
In MIT krb5 releases 1.14 and later, an authenticated attacker can
cause a null dereference in the KDC by sending a FAST TGS request with
no server field.
ticket: 9008 (new)
tags: pullup
target_version: 1.19-next
target_version: 1.18-next
(cherry picked from commit d775c95af7606a51bf79547a94fa52ddd1cb7f49)
(cherry picked from commit bb8fa495d00ccd931eec87a01b8920636cf7903e)
(cherry picked from commit dfe383f8251d0edc7e5e08ec5e4fdd9b7f902b2a)
---
src/kdc/do_tgs_req.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 463a9c0dd..7c596a111 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -208,6 +208,11 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
status = "FIND_FAST";
goto cleanup;
}
+ if (sprinc == NULL) {
+ status = "NULL_SERVER";
+ errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+ goto cleanup;
+ }
errcode = get_local_tgt(kdc_context, &sprinc->realm, header_server,
&local_tgt, &local_tgt_storage, &local_tgt_key);

@ -0,0 +1,113 @@
From 4e8579f0a41b66ed8029f21a52082e1c27ab3996 Mon Sep 17 00:00:00 2001
From: Joseph Sutton <josephsutton@catalyst.net.nz>
Date: Wed, 7 Jul 2021 11:47:44 +1200
Subject: [PATCH] Fix KDC null deref on bad encrypted challenge
The function ec_verify() in src/kdc/kdc_preauth_ec.c contains a check
to avoid further processing if the armor key is NULL. However, this
check is bypassed by a call to k5memdup0() which overwrites retval
with 0 if the allocation succeeds. If the armor key is NULL, a call
to krb5_c_fx_cf2_simple() will then dereference it, resulting in a
crash. Add a check before the k5memdup0() call to avoid overwriting
retval.
CVE-2021-36222:
In MIT krb5 releases 1.16 and later, an unauthenticated attacker can
cause a null dereference in the KDC by sending a request containing a
PA-ENCRYPTED-CHALLENGE padata element without using FAST.
[ghudson@mit.edu: trimmed patch; added test case; edited commit
message]
(cherry picked from commit fc98f520caefff2e5ee9a0026fdf5109944b3562)
ticket: 9007
version_fixed: 1.18.4
(cherry picked from commit c4a406095b3ea4a67ae5b8ea586cbe9abdbae76f)
---
src/kdc/kdc_preauth_ec.c | 3 ++-
src/tests/Makefile.in | 1 +
src/tests/t_cve-2021-36222.py | 46 +++++++++++++++++++++++++++++++++++
3 files changed, 49 insertions(+), 1 deletion(-)
create mode 100644 src/tests/t_cve-2021-36222.py
diff --git a/src/kdc/kdc_preauth_ec.c b/src/kdc/kdc_preauth_ec.c
index 7e636b3f9..43a9902cc 100644
--- a/src/kdc/kdc_preauth_ec.c
+++ b/src/kdc/kdc_preauth_ec.c
@@ -87,7 +87,8 @@ ec_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
}
/* Check for a configured FAST ec auth indicator. */
- realmstr = k5memdup0(realm.data, realm.length, &retval);
+ if (retval == 0)
+ realmstr = k5memdup0(realm.data, realm.length, &retval);
if (realmstr != NULL)
retval = profile_get_string(context->profile, KRB5_CONF_REALMS,
realmstr,
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 3f88f1713..0ffbebf56 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -158,6 +158,7 @@ check-pytests: unlockiter s4u2self
$(RUNPYTEST) $(srcdir)/t_cve-2012-1015.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_cve-2013-1416.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_cve-2013-1417.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_cve-2021-36222.py $(PYTESTFLAGS)
$(RM) au.log
$(RUNPYTEST) $(srcdir)/t_audit.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/jsonwalker.py -d $(srcdir)/au_dict.json \
diff --git a/src/tests/t_cve-2021-36222.py b/src/tests/t_cve-2021-36222.py
new file mode 100644
index 000000000..57e04993b
--- /dev/null
+++ b/src/tests/t_cve-2021-36222.py
@@ -0,0 +1,46 @@
+import socket
+from k5test import *
+
+realm = K5Realm()
+
+# CVE-2021-36222 KDC null dereference on encrypted challenge preauth
+# without FAST
+
+s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+a = (hostname, realm.portbase)
+
+m = ('6A81A0' '30819D' # [APPLICATION 10] SEQUENCE
+ 'A103' '0201' '05' # [1] pvno = 5
+ 'A203' '0201' '0A' # [2] msg-type = 10
+ 'A30E' '300C' # [3] padata = SEQUENCE OF
+ '300A' # SEQUENCE
+ 'A104' '0202' '008A' # [1] padata-type = PA-ENCRYPTED-CHALLENGE
+ 'A202' '0400' # [2] padata-value = ""
+ 'A48180' '307E' # [4] req-body = SEQUENCE
+ 'A007' '0305' '0000000000' # [0] kdc-options = 0
+ 'A120' '301E' # [1] cname = SEQUENCE
+ 'A003' '0201' '01' # [0] name-type = NT-PRINCIPAL
+ 'A117' '3015' # [1] name-string = SEQUENCE-OF
+ '1B06' '6B7262746774' # krbtgt
+ '1B0B' '4B5242544553542E434F4D'
+ # KRBTEST.COM
+ 'A20D' '1B0B' '4B5242544553542E434F4D'
+ # [2] realm = KRBTEST.COM
+ 'A320' '301E' # [3] sname = SEQUENCE
+ 'A003' '0201' '01' # [0] name-type = NT-PRINCIPAL
+ 'A117' '3015' # [1] name-string = SEQUENCE-OF
+ '1B06' '6B7262746774' # krbtgt
+ '1B0B' '4B5242544553542E434F4D'
+ # KRBTEST.COM
+ 'A511' '180F' '31393934303631303036303331375A'
+ # [5] till = 19940610060317Z
+ 'A703' '0201' '00' # [7] nonce = 0
+ 'A808' '3006' # [8] etype = SEQUENCE OF
+ '020112' '020111') # aes256-cts aes128-cts
+
+s.sendto(bytes.fromhex(m), a)
+
+# Make sure kinit still works.
+realm.kinit(realm.user_princ, password('user'))
+
+success('CVE-2021-36222 regression test')

@ -0,0 +1,45 @@
From 058dfbaed97c8e09ac4f3f7a1655b64ab3cf0144 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 21 Jul 2021 13:44:30 -0400
Subject: [PATCH] Fix defcred leak in krb5 gss_inquire_cred()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Commit 1cd2821c19b2b95e39d5fc2f451a035585a40fa5 altered the memory
management of krb5_gss_inquire_cred(), introducing defcred to act as
an owner pointer when the function must acquire a default credential.
The commit neglected to update the code to release the default cred
along the successful path. The old code does not trigger because
cred_handle is now reassigned, so the default credential is leaked.
Reported by Pavel Březina.
(a minimal alternative to commit 593e16448e1af23eef74689afe06a7bcc86e79c7)
ticket: 9016
version_fixed: 1.18.4
(cherry picked from commit b92be484630b38e26f5ee4bd67973fbd7627009c)
---
src/lib/gssapi/krb5/inq_cred.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c
index a8f2541102..cd8384d08c 100644
--- a/src/lib/gssapi/krb5/inq_cred.c
+++ b/src/lib/gssapi/krb5/inq_cred.c
@@ -197,9 +197,7 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
mechs = GSS_C_NO_OID_SET;
}
- if (cred_handle == GSS_C_NO_CREDENTIAL)
- krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred);
-
+ krb5_gss_release_cred(minor_status, &defcred);
krb5_free_context(context);
*minor_status = 0;
return((lifetime == 0)?GSS_S_CREDENTIALS_EXPIRED:GSS_S_COMPLETE);
--
2.44.0

@ -0,0 +1,106 @@
From d2477aa606ad590ca4097941bb6c2e1955b2a8c8 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 17 Oct 2022 20:25:11 -0400
Subject: [PATCH] Fix integer overflows in PAC parsing
In krb5_parse_pac(), check for buffer counts large enough to threaten
integer overflow in the header length and memory length calculations.
Avoid potential integer overflows when checking the length of each
buffer.
CVE-2022-42898:
In MIT krb5 releases 1.8 and later, an authenticated attacker may be
able to cause a KDC or kadmind process to crash by reading beyond the
bounds of allocated memory, creating a denial of service. A
privileged attacker may similarly be able to cause a Kerberos or GSS
application service to crash. On 32-bit platforms, an attacker can
also cause insufficient memory to be allocated for the result,
potentially leading to remote code execution in a KDC, kadmind, or GSS
or Kerberos application server process. An attacker with the
privileges of a cross-realm KDC may be able to extract secrets from
the KDC process's memory by having them copied into the PAC of a new
ticket.
ticket: 9074 (new)
tags: pullup
target_version: 1.20-next
target_version: 1.19-next
---
src/lib/krb5/krb/pac.c | 9 +++++++--
src/lib/krb5/krb/t_pac.c | 18 ++++++++++++++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
index 950beda657..1b9ef12276 100644
--- a/src/lib/krb5/krb/pac.c
+++ b/src/lib/krb5/krb/pac.c
@@ -27,6 +27,8 @@
#include "k5-int.h"
#include "authdata.h"
+#define MAX_BUFFERS 4096
+
/* draft-brezak-win2k-krb-authz-00 */
/*
@@ -316,6 +318,9 @@ krb5_pac_parse(krb5_context context,
if (version != 0)
return EINVAL;
+ if (cbuffers < 1 || cbuffers > MAX_BUFFERS)
+ return ERANGE;
+
header_len = PACTYPE_LENGTH + (cbuffers * PAC_INFO_BUFFER_LENGTH);
if (len < header_len)
return ERANGE;
@@ -348,8 +353,8 @@ krb5_pac_parse(krb5_context context,
krb5_pac_free(context, pac);
return EINVAL;
}
- if (buffer->Offset < header_len ||
- buffer->Offset + buffer->cbBufferSize > len) {
+ if (buffer->Offset < header_len || buffer->Offset > len ||
+ buffer->cbBufferSize > len - buffer->Offset) {
krb5_pac_free(context, pac);
return ERANGE;
}
diff --git a/src/lib/krb5/krb/t_pac.c b/src/lib/krb5/krb/t_pac.c
index ee47152ee4..ccd165380d 100644
--- a/src/lib/krb5/krb/t_pac.c
+++ b/src/lib/krb5/krb/t_pac.c
@@ -431,6 +431,16 @@ static const unsigned char s4u_pac_ent_xrealm[] = {
0x8a, 0x81, 0x9c, 0x9c, 0x00, 0x00, 0x00, 0x00
};
+static const unsigned char fuzz1[] = {
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf5
+};
+
+static const unsigned char fuzz2[] = {
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x20
+};
+
static const char *s4u_principal = "w2k8u@ACME.COM";
static const char *s4u_enterprise = "w2k8u@abc@ACME.COM";
@@ -646,6 +656,14 @@ main(int argc, char **argv)
krb5_free_principal(context, sep);
}
+ /* Check problematic PACs found by fuzzing. */
+ ret = krb5_pac_parse(context, fuzz1, sizeof(fuzz1), &pac);
+ if (!ret)
+ err(context, ret, "krb5_pac_parse should have failed");
+ ret = krb5_pac_parse(context, fuzz2, sizeof(fuzz2), &pac);
+ if (!ret)
+ err(context, ret, "krb5_pac_parse should have failed");
+
/*
* Test empty free
*/
--
2.37.3

@ -0,0 +1,60 @@
From 7a87189f7bdabc144e22d4caa6a0785a06416d8f Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 24 Jul 2020 16:05:24 -0400
Subject: [PATCH] Fix leak in KERB_AP_OPTIONS_CBT server support
In check_cbt(), use a local variable to hold the retrieved authdata
list, and free it before returning.
ticket: 8900
(cherry picked from commit bf2ddff13c178e0c291f8fb382b040080d159e4f)
(cherry picked from commit 044e2209586fd1935d9a637df76d52f48c4f3e6e)
---
src/lib/gssapi/krb5/accept_sec_context.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 175a24c4e..3d5b84b15 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -433,27 +433,30 @@ static const uint8_t null_cb[CB_MD5_LEN];
/* Look for AP_OPTIONS in authdata. If present and the options include
* KERB_AP_OPTIONS_CBT, set *cbt_out to true. */
static krb5_error_code
-check_cbt(krb5_context context, krb5_authdata **authdata,
+check_cbt(krb5_context context, krb5_authdata *const *authdata,
krb5_boolean *cbt_out)
{
krb5_error_code code;
+ krb5_authdata **ad;
uint32_t ad_ap_options;
const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
*cbt_out = FALSE;
code = krb5_find_authdata(context, NULL, authdata,
- KRB5_AUTHDATA_AP_OPTIONS, &authdata);
- if (code || authdata == NULL)
+ KRB5_AUTHDATA_AP_OPTIONS, &ad);
+ if (code || ad == NULL)
return code;
- if (authdata[1] != NULL || authdata[0]->length != 4)
- return KRB5KRB_AP_ERR_MSG_TYPE;
+ if (ad[1] != NULL || ad[0]->length != 4) {
+ code = KRB5KRB_AP_ERR_MSG_TYPE;
+ } else {
+ ad_ap_options = load_32_le(ad[0]->contents);
+ if (ad_ap_options & KERB_AP_OPTIONS_CBT)
+ *cbt_out = TRUE;
+ }
- ad_ap_options = load_32_le(authdata[0]->contents);
- if (ad_ap_options & KERB_AP_OPTIONS_CBT)
- *cbt_out = TRUE;
-
- return 0;
+ krb5_free_authdata(context, ad);
+ return code;
}
/*

@ -1,4 +1,4 @@
From d230c72573430803c569817a71b79be8656fa6c5 Mon Sep 17 00:00:00 2001
From efb3acd20cbe6330439635a9f297b9dae8a0a5d3 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 5 Mar 2024 19:53:07 -0500
Subject: [PATCH] Fix two unlikely memory leaks
@ -15,8 +15,8 @@ fails.
(cherry picked from commit c5f9c816107f70139de11b38aa02db2f1774ee0d)
---
src/lib/gssapi/krb5/k5sealv3.c | 56 +++++++++++++++-------------------
src/lib/rpc/pmap_rmt.c | 10 +++---
2 files changed, 29 insertions(+), 37 deletions(-)
src/lib/rpc/pmap_rmt.c | 9 +++---
2 files changed, 29 insertions(+), 36 deletions(-)
diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c
index 3b4f8cb837..e881eee835 100644
@ -180,16 +180,15 @@ index 3b4f8cb837..e881eee835 100644
}
diff --git a/src/lib/rpc/pmap_rmt.c b/src/lib/rpc/pmap_rmt.c
index 434e4eea65..f55ca46c60 100644
index 8c7e30c21a..0748af34a7 100644
--- a/src/lib/rpc/pmap_rmt.c
+++ b/src/lib/rpc/pmap_rmt.c
@@ -161,12 +161,12 @@ xdr_rmtcallres(
@@ -160,11 +160,12 @@ xdr_rmtcallres(
caddr_t port_ptr;
port_ptr = (caddr_t)(void *)crp->port_ptr;
- if (xdr_reference(xdrs, &port_ptr, sizeof (uint32_t),
- (xdrproc_t)xdr_u_int32) &&
- xdr_u_int32(xdrs, &crp->resultslen)) {
- xdr_u_int32) && xdr_u_int32(xdrs, &crp->resultslen)) {
- crp->port_ptr = (uint32_t *)(void *)port_ptr;
+ if (!xdr_reference(xdrs, &port_ptr, sizeof (uint32_t),
+ (xdrproc_t)xdr_u_int32))

@ -0,0 +1,38 @@
From 5a0833a3f3b1c44edd08425d98f682b96ad7a01e Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Thu, 14 May 2020 15:01:18 -0400
Subject: [PATCH] Fix typo ("in in") in the ksu man page
(cherry picked from commit 1011841acdc1020f308ef4f569c6622f279d8c3f)
(cherry picked from commit 8de669742ae4190542741f0dc61119a6a0dad666)
---
doc/user/user_commands/ksu.rst | 2 +-
src/man/ksu.man | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/user/user_commands/ksu.rst b/doc/user/user_commands/ksu.rst
index 8d6c7ef79..933738229 100644
--- a/doc/user/user_commands/ksu.rst
+++ b/doc/user/user_commands/ksu.rst
@@ -155,7 +155,7 @@ wrong password is typed in, ksu fails.
.. note::
During authentication, only the tickets that could be
- obtained without providing a password are cached in in the
+ obtained without providing a password are cached in the
source cache.
diff --git a/src/man/ksu.man b/src/man/ksu.man
index 81e34815d..8d4c6a359 100644
--- a/src/man/ksu.man
+++ b/src/man/ksu.man
@@ -176,7 +176,7 @@ wrong password is typed in, ksu fails.
.INDENT 0.0
.INDENT 3.5
During authentication, only the tickets that could be
-obtained without providing a password are cached in in the
+obtained without providing a password are cached in the
source cache.
.UNINDENT
.UNINDENT

@ -1,4 +1,4 @@
From 28009fda028c489ae38902b2c513c4208889f043 Mon Sep 17 00:00:00 2001
From c73e8ed9f89fdc709d15656b6431492d43de94ce Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 14 Jun 2024 10:56:12 -0400
Subject: [PATCH] Fix vulnerabilities in GSS message token handling
@ -200,7 +200,7 @@ index 3ce2a90ce9..6a6585d9af 100644
switch (toktype2) {
case KG2_TOK_MIC_MSG:
diff --git a/src/tests/gssapi/t_invalid.c b/src/tests/gssapi/t_invalid.c
index e08c0039f8..a052b8ab6e 100644
index fb8fe55111..8192935099 100644
--- a/src/tests/gssapi/t_invalid.c
+++ b/src/tests/gssapi/t_invalid.c
@@ -36,31 +36,41 @@
@ -274,7 +274,7 @@ index e08c0039f8..a052b8ab6e 100644
+/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key.
+ * The context takes ownership of subkey. */
static gss_ctx_id_t
-make_fake_cfx_context(void)
-make_fake_cfx_context()
+make_fake_cfx_context(krb5_key subkey)
{
gss_union_ctx_id_t uctx;
@ -288,7 +288,7 @@ index e08c0039f8..a052b8ab6e 100644
kgctx->established = 1;
kgctx->proto = 1;
if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0)
@@ -116,15 +134,10 @@ make_fake_cfx_context(void)
@@ -116,15 +134,10 @@ make_fake_cfx_context()
kgctx->sealalg = -1;
kgctx->signalg = -1;
@ -505,7 +505,7 @@ index e08c0039f8..a052b8ab6e 100644
memcpy(in.value, value, len);
in.length = len;
(void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,
@@ -424,11 +569,23 @@ test_short_encapsulation(void)
@@ -424,11 +569,23 @@ test_short_encapsulation()
int
main(int argc, char **argv)
{

@ -1,4 +1,4 @@
From 023dcf87d34e29649dd76d33ce7d896c2b6f61d2 Mon Sep 17 00:00:00 2001
From aad00d346e5c7923287fc0016a37b49c4618d78e Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 22 Aug 2024 17:15:50 +0200
Subject: [PATCH] Generate and verify message MACs in libkrad
@ -43,12 +43,12 @@ target_version: 1.21-next
11 files changed, 311 insertions(+), 31 deletions(-)
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 69d6a6f569..b7789a2dd8 100644
index 9d5e41ca2c..d062617268 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -2403,4 +2403,9 @@ krb5_boolean
k5_sname_compare(krb5_context context, krb5_const_principal sname,
krb5_const_principal princ);
@@ -2415,4 +2415,9 @@ void k5_change_error_message_code(krb5_context ctx, krb5_error_code oldcode,
#define k5_prependmsg krb5_prepend_error_message
#define k5_wrapmsg krb5_wrap_error_message
+/* Generate an HMAC-MD5 keyed checksum as specified by RFC 2104. */
+krb5_error_code
@ -93,10 +93,10 @@ index ec024f3966..a809388549 100644
+ return krb5int_hmac_keyblock(hash, &keyblock, data, num_data, output);
+}
diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports
index d8ffa63304..00e0ce1812 100644
index 9db1813810..b4dcd29937 100644
--- a/src/lib/crypto/libk5crypto.exports
+++ b/src/lib/crypto/libk5crypto.exports
@@ -102,3 +102,4 @@ krb5_c_prfplus
@@ -107,3 +107,4 @@ krb5_c_prfplus
krb5_c_derive_prfplus
k5_enctype_to_ssf
krb5int_c_deprecated_enctype
@ -215,10 +215,10 @@ index 6ec031e320..e5457ebfd7 100644
*outlen = i;
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
index a17b6f39b1..ca66f3ec68 100644
index b086598fb2..f3e4a1d8d3 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -49,6 +49,8 @@
@@ -45,6 +45,8 @@
#define UCHAR_MAX 255
#endif
@ -227,7 +227,7 @@ index a17b6f39b1..ca66f3ec68 100644
/* RFC 2865 */
#define MAX_ATTRSIZE (UCHAR_MAX - 2)
#define MAX_ATTRSETSIZE (KRAD_PACKET_SIZE_MAX - 20)
@@ -79,10 +81,11 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
@@ -75,10 +77,11 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
krad_attr type, const krb5_data *in,
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
@ -242,7 +242,7 @@ index a17b6f39b1..ca66f3ec68 100644
krb5_boolean *is_fips);
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
index c5446b890c..3c1a4d507e 100644
index fc2d248001..257bbc6345 100644
--- a/src/lib/krad/packet.c
+++ b/src/lib/krad/packet.c
@@ -36,6 +36,7 @@
@ -538,10 +538,10 @@ index c5446b890c..3c1a4d507e 100644
}
diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
index 4cdb8b7d8e..f9c66509bd 100644
index 0f95762534..9a70529dc5 100644
--- a/src/lib/krad/t_attrset.c
+++ b/src/lib/krad/t_attrset.c
@@ -63,7 +63,7 @@ main(void)
@@ -63,7 +63,7 @@ main()
noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp));
/* Encode attrset. */
@ -551,7 +551,7 @@ index 4cdb8b7d8e..f9c66509bd 100644
krad_attrset_free(set);
diff --git a/src/lib/krad/t_daemon.py b/src/lib/krad/t_daemon.py
index 4a3de079c7..647d4894eb 100755
index 7668cd7f87..7fa0449a3c 100755
--- a/src/lib/krad/t_daemon.py
+++ b/src/lib/krad/t_daemon.py
@@ -40,6 +40,7 @@ DICTIONARY = """
@ -564,7 +564,7 @@ index 4a3de079c7..647d4894eb 100755
class TestServer(server.Server):
@@ -52,7 +53,7 @@ class TestServer(server.Server):
if key == "User-Password":
passwd = [pkt.PwDecrypt(x) for x in pkt[key]]
passwd = map(pkt.PwDecrypt, pkt[key])
- reply = self.CreateReplyPacket(pkt)
+ reply = self.CreateReplyPacket(pkt, message_authenticator=True)
@ -604,7 +604,7 @@ index c22489144f..104b6507a2 100644
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
index c3b820a411..dd5cdc5c26 100755
index cba871a0f2..1ec916598c 100755
--- a/src/tests/t_otp.py
+++ b/src/tests/t_otp.py
@@ -49,6 +49,7 @@ ATTRIBUTE User-Name 1 string

@ -0,0 +1,38 @@
From 42e29f27ce64fece2839bcce910813e97ca31210 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Wed, 15 Jul 2020 15:42:20 -0400
Subject: [PATCH] Ignore bad enctypes in krb5_string_to_keysalts()
Fixes a problem where the presence of legacy/unrecognized keysalts in
supported_enctypes would prevent the kadmin programs from starting.
[ghudson@mit.edu: ideally we would put a warning in the kadmind log,
but that is difficult to do when the parsing is done inside a library.
Even adding a trace log is difficult because the kadm5 str_conv
functions do not accept contexts.]
ticket: 8929 (new)
(cherry picked from commit be5396ada0e8dabd68bd0aceb733cfca39a609bc)
(cherry picked from commit 3f873868fb08b77da2d30e164a0ef6c71c17c607)
---
src/lib/kadm5/str_conv.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/lib/kadm5/str_conv.c b/src/lib/kadm5/str_conv.c
index 7cf51d316..798295606 100644
--- a/src/lib/kadm5/str_conv.c
+++ b/src/lib/kadm5/str_conv.c
@@ -340,9 +340,10 @@ krb5_string_to_keysalts(const char *string, const char *tupleseps,
while ((ksp = strtok_r(p, tseps, &tlasts)) != NULL) {
/* Pass a null pointer to subsequent calls to strtok_r(). */
p = NULL;
- ret = string_to_keysalt(ksp, ksaltseps, &etype, &stype);
- if (ret)
- goto cleanup;
+
+ /* Discard unrecognized keysalts. */
+ if (string_to_keysalt(ksp, ksaltseps, &etype, &stype) != 0)
+ continue;
/* Ignore duplicate keysalts if caller asks. */
if (!dups && krb5_keysalt_is_present(ksalts, nksalts, etype, stype))

@ -0,0 +1,92 @@
From b8bff4973a6642af80cbbc1bc03a52cb0d4e6247 Mon Sep 17 00:00:00 2001
From: Alexander Scheel <ascheel@redhat.com>
Date: Wed, 5 Jul 2017 11:38:30 -0400
Subject: [PATCH] Implement GSS_C_CHANNEL_BOUND_FLAG
Define a new channel-bound GSS return flag, and set it in the krb5
mech if the initiator sent channel bindings matching the acceptor's.
Do not error out if the acceptor specifies channel bindings and the
initiator does not send them.
[ghudson@mit.edu: simplified code changes; fleshed out commit message]
[iboukris: cherry-picked from another PR and reduced in scope]
ticket: 8899 (new)
(cherry picked from commit 429a31146083fac21958631c2af572b08ec91022)
(cherry picked from commit 3ea1d6296ced3a998e79356f9be212e4c5e6a5d5)
---
src/lib/gssapi/generic/gssapi_ext.h | 2 ++
src/lib/gssapi/krb5/accept_sec_context.c | 18 +++++++++++++-----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
index 218456e44..c675e8ebb 100644
--- a/src/lib/gssapi/generic/gssapi_ext.h
+++ b/src/lib/gssapi/generic/gssapi_ext.h
@@ -595,6 +595,8 @@ gss_store_cred_into(
* attribute (along with any applicable RFC 5587 attributes).
*/
+#define GSS_C_CHANNEL_BOUND_FLAG 2048 /* 0x00000800 */
+
OM_uint32 KRB5_CALLCONV
gssspi_query_meta_data(
OM_uint32 *minor_status,
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 70dd7fc0c..9d3e2f4fe 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -427,6 +427,9 @@ kg_process_extension(krb5_context context,
GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE | \
GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG)
+/* A zero-value channel binding, for comparison */
+static const uint8_t null_cb[CB_MD5_LEN];
+
/*
* The krb5 GSS mech appropriates the authenticator checksum field from RFC
* 4120 to store structured data instead of a checksum, indicated with checksum
@@ -435,9 +438,10 @@ kg_process_extension(krb5_context context,
*
* Interpret the checksum. Read delegated creds into *deleg_out if it is not
* NULL. Set *flags_out to the allowed subset of token flags, plus
- * GSS_C_DELEG_FLAG if a delegated credential was present. Process any
- * extensions found using exts. On error, set *code_out to a krb5_error code
- * for use as a minor status value.
+ * GSS_C_DELEG_FLAG if a delegated credential was present and
+ * GSS_C_CHANNEL_BOUND_FLAG if matching channel bindings are present. Process
+ * any extensions found using exts. On error, set *code_out to a krb5_error
+ * code for use as a minor status value.
*/
static OM_uint32
process_checksum(OM_uint32 *minor_status, krb5_context context,
@@ -450,7 +454,7 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
krb5_error_code code = 0;
OM_uint32 status, option_id, token_flags;
size_t cb_len, option_len;
- krb5_boolean valid;
+ krb5_boolean valid, token_cb_present = FALSE, cb_match = FALSE;
krb5_key subkey;
krb5_data option, empty = empty_data();
krb5_checksum cb_cksum;
@@ -516,7 +520,9 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
goto fail;
}
assert(cb_cksum.length == cb_len);
- if (k5_bcmp(token_cb, cb_cksum.contents, cb_len) != 0) {
+ token_cb_present = (k5_bcmp(token_cb, null_cb, cb_len) != 0);
+ cb_match = (k5_bcmp(token_cb, cb_cksum.contents, cb_len) == 0);
+ if (token_cb_present && !cb_match) {
status = GSS_S_BAD_BINDINGS;
goto fail;
}
@@ -525,6 +531,8 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
/* Read the token flags and accept some of them as context flags. */
token_flags = k5_input_get_uint32_le(&in);
*flags_out = token_flags & INITIATOR_FLAGS;
+ if (cb_match)
+ *flags_out |= GSS_C_CHANNEL_BOUND_FLAG;
/* Read the delegated credential if present. */
if (in.len >= 4 && (token_flags & GSS_C_DELEG_FLAG)) {

@ -0,0 +1,103 @@
From b37714a1b9138c0258d357931215fbd5ca7fa72b Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Mon, 9 Mar 2020 16:04:21 +0100
Subject: [PATCH] Implement KERB_AP_OPTIONS_CBT (server side)
Add server support for Microsoft's KERB_AP_OPTIONS_CBT as described in
MS-KILE. If the client includes the AP option in the authenticator
authdata and the server passed channel bindings, require the bindings
to match.
[ghudson@mit.edu: refactored to put more logic in the helper function;
added a comment; clarified commit message]
ticket: 8900 (new)
(cherry picked from commit 4f7c77b64a048ca5e3199b26b31493698c777a9c)
(cherry picked from commit 6407bf087fe53088d91efd09df736e979cd4e8db)
---
src/include/krb5/krb5.hin | 1 +
src/lib/gssapi/krb5/accept_sec_context.c | 45 +++++++++++++++++++++++-
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index f8269fb17..9264bede1 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -1915,6 +1915,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
#define KRB5_AUTHDATA_SIGNTICKET 512 /**< formerly 142 in krb5 1.8 */
#define KRB5_AUTHDATA_FX_ARMOR 71
#define KRB5_AUTHDATA_AUTH_INDICATOR 97
+#define KRB5_AUTHDATA_AP_OPTIONS 143
/** @} */ /* end of KRB5_AUTHDATA group */
/* password change constants */
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 9d3e2f4fe..175a24c4e 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -430,6 +430,32 @@ kg_process_extension(krb5_context context,
/* A zero-value channel binding, for comparison */
static const uint8_t null_cb[CB_MD5_LEN];
+/* Look for AP_OPTIONS in authdata. If present and the options include
+ * KERB_AP_OPTIONS_CBT, set *cbt_out to true. */
+static krb5_error_code
+check_cbt(krb5_context context, krb5_authdata **authdata,
+ krb5_boolean *cbt_out)
+{
+ krb5_error_code code;
+ uint32_t ad_ap_options;
+ const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
+
+ *cbt_out = FALSE;
+
+ code = krb5_find_authdata(context, NULL, authdata,
+ KRB5_AUTHDATA_AP_OPTIONS, &authdata);
+ if (code || authdata == NULL)
+ return code;
+ if (authdata[1] != NULL || authdata[0]->length != 4)
+ return KRB5KRB_AP_ERR_MSG_TYPE;
+
+ ad_ap_options = load_32_le(authdata[0]->contents);
+ if (ad_ap_options & KERB_AP_OPTIONS_CBT)
+ *cbt_out = TRUE;
+
+ return 0;
+}
+
/*
* The krb5 GSS mech appropriates the authenticator checksum field from RFC
* 4120 to store structured data instead of a checksum, indicated with checksum
@@ -454,7 +480,7 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
krb5_error_code code = 0;
OM_uint32 status, option_id, token_flags;
size_t cb_len, option_len;
- krb5_boolean valid, token_cb_present = FALSE, cb_match = FALSE;
+ krb5_boolean valid, client_cbt, token_cb_present = FALSE, cb_match = FALSE;
krb5_key subkey;
krb5_data option, empty = empty_data();
krb5_checksum cb_cksum;
@@ -582,6 +608,23 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
}
}
+ /*
+ * If the client asserts the KERB_AP_OPTIONS_CBT flag (from MS-KILE) in the
+ * authenticator authdata, and the acceptor passed channel bindings,
+ * require matching channel bindings from the client. The intent is to
+ * prevent an authenticator generated for use outside of a TLS channel from
+ * being used inside of one.
+ */
+ code = check_cbt(context, authenticator->authorization_data, &client_cbt);
+ if (code) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if (client_cbt && acceptor_cb != GSS_C_NO_CHANNEL_BINDINGS && !cb_match) {
+ status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
status = GSS_S_COMPLETE;
fail:

@ -0,0 +1,31 @@
From 01b93a5522fd0e402401bf6ed3c1ebfde613965e Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 9 Jun 2020 16:23:37 -0400
Subject: [PATCH] Improve negoex_parse_token() code hygiene
If the while loop in negoex_parse_token() runs for zero iterations,
major will be used initialized. Currently this cannot happen, but
only because both of the call sites check for zero-length tokens.
Initialize major for safety.
[ghudson@mit.edu: rewrote commit message]
(cherry picked from commit 4f91b6f8fa6fe1de662b3fdac0d59b7758ec642a)
(cherry picked from commit c726a72c68244129eb08b840b92144acfa776573)
---
src/lib/gssapi/spnego/negoex_util.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/gssapi/spnego/negoex_util.c b/src/lib/gssapi/spnego/negoex_util.c
index 700368456..99580fd79 100644
--- a/src/lib/gssapi/spnego/negoex_util.c
+++ b/src/lib/gssapi/spnego/negoex_util.c
@@ -454,7 +454,7 @@ negoex_parse_token(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
gss_const_buffer_t token,
struct negoex_message **messages_out, size_t *count_out)
{
- OM_uint32 major;
+ OM_uint32 major = GSS_S_COMPLETE;
size_t count = 0;
struct k5input in;
struct negoex_message *messages = NULL, *newptr;

@ -0,0 +1,28 @@
From b96983de501f185a06e8b3d2909ef71033bd9e48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 30 Mar 2021 14:35:28 +0200
Subject: [PATCH] Make KCM iteration fallback work with sssd-kcm
sssd-kcm returns KRB5_CC_IO if the operation code is not known.
ticket: 8990
(cherry picked from commit 06afae820a44c1dc96ad88a0b16c3e50bc938b2a)
(cherry picked from commit 2dbca7e14c945d6394e0e05f285a068dcd541295)
(cherry picked from commit f7702c5b11bdd186d03fed32568c9a252d049d44)
---
src/lib/krb5/ccache/cc_kcm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
index 4141140c3..dae622feb 100644
--- a/src/lib/krb5/ccache/cc_kcm.c
+++ b/src/lib/krb5/ccache/cc_kcm.c
@@ -876,7 +876,7 @@ kcm_start_seq_get(krb5_context context, krb5_ccache cache,
ret = kcmreq_get_cred_list(&req, &creds);
if (ret)
goto cleanup;
- } else if (ret == KRB5_FCC_INTERNAL) {
+ } else if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
/* Fall back to GET_CRED_UUID_LIST. */
kcmreq_free(&req);
kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);

@ -0,0 +1,365 @@
From 5d541f1f0b468b1c976acf8ec2359bd0c8c73be7 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 19 Jan 2022 19:46:08 +0100
Subject: [PATCH] Make kprop work for dump files larger than 4GB
If the dump file size does not fit in 32 bits, encode four zero bytes
(forcing an error for unmodified kpropd) followed by the size in the
next 64 bits.
Add a functional test case, but only run it when an environment
variable is set, as processing a 4GB dump file is too
resource-intensive for make check.
[ghudson@mit.edu: edited comments and commit message; eliminated use
of defined constant in some cases; added test case]
ticket: 9053 (new)
---
src/kprop/kprop.c | 37 +++++++++++++++++++++----------------
src/kprop/kprop.h | 12 ++++++++++++
src/kprop/kprop_util.c | 42 ++++++++++++++++++++++++++++++++++++++++++
src/kprop/kpropd.c | 33 +++++++++++++++++++++------------
src/tests/t_kprop.py | 34 ++++++++++++++++++++++++++++++++++
5 files changed, 130 insertions(+), 28 deletions(-)
diff --git a/src/kprop/kprop.c b/src/kprop/kprop.c
index 0b53aae7e..5adb4d31f 100644
--- a/src/kprop/kprop.c
+++ b/src/kprop/kprop.c
@@ -25,6 +25,7 @@
*/
#include "k5-int.h"
+#include <inttypes.h>
#include <locale.h>
#include <sys/file.h>
#include <signal.h>
@@ -71,11 +72,11 @@ static void open_connection(krb5_context context, char *host, int *fd_out);
static void kerberos_authenticate(krb5_context context,
krb5_auth_context *auth_context, int fd,
krb5_principal me, krb5_creds **new_creds);
-static int open_database(krb5_context context, char *data_fn, int *size);
+static int open_database(krb5_context context, char *data_fn, off_t *size);
static void close_database(krb5_context context, int fd);
static void xmit_database(krb5_context context,
krb5_auth_context auth_context, krb5_creds *my_creds,
- int fd, int database_fd, int in_database_size);
+ int fd, int database_fd, off_t in_database_size);
static void send_error(krb5_context context, krb5_creds *my_creds, int fd,
char *err_text, krb5_error_code err_code);
static void update_last_prop_file(char *hostname, char *file_name);
@@ -90,7 +91,8 @@ static void usage()
int
main(int argc, char **argv)
{
- int fd, database_fd, database_size;
+ int fd, database_fd;
+ off_t database_size;
krb5_error_code retval;
krb5_context context;
krb5_creds *my_creds;
@@ -339,7 +341,7 @@ kerberos_authenticate(krb5_context context, krb5_auth_context *auth_context,
* in the size of the database file.
*/
static int
-open_database(krb5_context context, char *data_fn, int *size)
+open_database(krb5_context context, char *data_fn, off_t *size)
{
struct stat stbuf, stbuf_ok;
char *data_ok_fn;
@@ -413,19 +415,18 @@ close_database(krb5_context context, int fd)
static void
xmit_database(krb5_context context, krb5_auth_context auth_context,
krb5_creds *my_creds, int fd, int database_fd,
- int in_database_size)
+ off_t in_database_size)
{
krb5_int32 n;
krb5_data inbuf, outbuf;
- char buf[KPROP_BUFSIZ];
+ char buf[KPROP_BUFSIZ], dbsize_buf[KPROP_DBSIZE_MAX_BUFSIZ];
krb5_error_code retval;
krb5_error *error;
- krb5_ui_4 database_size = in_database_size, send_size, sent_size;
+ uint64_t database_size = in_database_size, send_size, sent_size;
/* Send over the size. */
- send_size = htonl(database_size);
- inbuf.data = (char *)&send_size;
- inbuf.length = sizeof(send_size); /* must be 4, really */
+ inbuf = make_data(dbsize_buf, sizeof(dbsize_buf));
+ encode_database_size(database_size, &inbuf);
/* KPROP_CKSUMTYPE */
retval = krb5_mk_safe(context, auth_context, &inbuf, &outbuf, NULL);
if (retval) {
@@ -460,7 +461,7 @@ xmit_database(krb5_context context, krb5_auth_context auth_context,
retval = krb5_mk_priv(context, auth_context, &inbuf, &outbuf, NULL);
if (retval) {
snprintf(buf, sizeof(buf),
- "while encoding database block starting at %d",
+ "while encoding database block starting at %"PRIu64,
sent_size);
com_err(progname, retval, "%s", buf);
send_error(context, my_creds, fd, buf, retval);
@@ -471,14 +472,14 @@ xmit_database(krb5_context context, krb5_auth_context auth_context,
if (retval) {
krb5_free_data_contents(context, &outbuf);
com_err(progname, retval,
- _("while sending database block starting at %d"),
+ _("while sending database block starting at %"PRIu64),
sent_size);
exit(1);
}
krb5_free_data_contents(context, &outbuf);
sent_size += n;
if (debug)
- printf("%d bytes sent.\n", sent_size);
+ printf("%"PRIu64" bytes sent.\n", sent_size);
}
if (sent_size != database_size) {
com_err(progname, 0, _("Premature EOF found for database file!"));
@@ -533,10 +534,14 @@ xmit_database(krb5_context context, krb5_auth_context auth_context,
exit(1);
}
- memcpy(&send_size, outbuf.data, sizeof(send_size));
- send_size = ntohl(send_size);
+ retval = decode_database_size(&outbuf, &send_size);
+ if (retval) {
+ com_err(progname, retval, _("malformed sent database size message"));
+ exit(1);
+ }
if (send_size != database_size) {
- com_err(progname, 0, _("Kpropd sent database size %d, expecting %d"),
+ com_err(progname, 0, _("Kpropd sent database size %"PRIu64
+ ", expecting %"PRIu64),
send_size, database_size);
exit(1);
}
diff --git a/src/kprop/kprop.h b/src/kprop/kprop.h
index 75331cc8a..3a319b535 100644
--- a/src/kprop/kprop.h
+++ b/src/kprop/kprop.h
@@ -32,6 +32,7 @@
#define KPROP_PROT_VERSION "kprop5_01"
#define KPROP_BUFSIZ 32768
+#define KPROP_DBSIZE_MAX_BUFSIZ 12 /* max length of an encoded DB size */
/* pathnames are in osconf.h, included via k5-int.h */
@@ -41,3 +42,14 @@ int sockaddr2krbaddr(krb5_context context, int family, struct sockaddr *sa,
krb5_error_code
sn2princ_realm(krb5_context context, const char *hostname, const char *sname,
const char *realm, krb5_principal *princ_out);
+
+/*
+ * Encode size in four bytes (for backward compatibility) if it fits; otherwise
+ * use the larger encoding. buf must be allocated with at least
+ * KPROP_DBSIZE_MAX_BUFSIZ bytes.
+ */
+void encode_database_size(uint64_t size, krb5_data *buf);
+
+/* Decode a database size. Return KRB5KRB_ERR_GENERIC if buf has an invalid
+ * length or did not encode a 32-bit size compactly. */
+krb5_error_code decode_database_size(const krb5_data *buf, uint64_t *size_out);
diff --git a/src/kprop/kprop_util.c b/src/kprop/kprop_util.c
index c32d174b9..9d6b25389 100644
--- a/src/kprop/kprop_util.c
+++ b/src/kprop/kprop_util.c
@@ -96,3 +96,45 @@ sn2princ_realm(krb5_context context, const char *hostname, const char *sname,
(*princ_out)->type = KRB5_NT_SRV_HST;
return ret;
}
+
+void
+encode_database_size(uint64_t size, krb5_data *buf)
+{
+ assert(buf->length >= 12);
+ if (size > 0 && size <= UINT32_MAX) {
+ /* Encode in 32 bits for backward compatibility. */
+ store_32_be(size, buf->data);
+ buf->length = 4;
+ } else {
+ /* Set the first 32 bits to 0 and encode in the following 64 bits. */
+ store_32_be(0, buf->data);
+ store_64_be(size, buf->data + 4);
+ buf->length = 12;
+ }
+}
+
+krb5_error_code
+decode_database_size(const krb5_data *buf, uint64_t *size_out)
+{
+ uint64_t size;
+
+ if (buf->length == 12) {
+ /* A 12-byte buffer must have the first four bytes zeroed. */
+ if (load_32_be(buf->data) != 0)
+ return KRB5KRB_ERR_GENERIC;
+
+ /* The size is stored in the next 64 bits. Values from 1..2^32-1 must
+ * be encoded in four bytes. */
+ size = load_64_be(buf->data + 4);
+ if (size > 0 && size <= UINT32_MAX)
+ return KRB5KRB_ERR_GENERIC;
+ } else if (buf->length == 4) {
+ size = load_32_be(buf->data);
+ } else {
+ /* Invalid buffer size. */
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+ *size_out = size;
+ return 0;
+}
diff --git a/src/kprop/kpropd.c b/src/kprop/kpropd.c
index 356e3e0e6..a83a86866 100644
--- a/src/kprop/kpropd.c
+++ b/src/kprop/kpropd.c
@@ -55,6 +55,7 @@
#include "com_err.h"
#include "fake-addrinfo.h"
+#include <inttypes.h>
#include <locale.h>
#include <ctype.h>
#include <sys/file.h>
@@ -1354,9 +1355,10 @@ static void
recv_database(krb5_context context, int fd, int database_fd,
krb5_data *confmsg)
{
- krb5_ui_4 database_size, received_size;
+ uint64_t database_size, received_size;
int n;
char buf[1024];
+ char dbsize_buf[KPROP_DBSIZE_MAX_BUFSIZ];
krb5_data inbuf, outbuf;
krb5_error_code retval;
@@ -1378,10 +1380,17 @@ recv_database(krb5_context context, int fd, int database_fd,
_("while decoding database size from client"));
exit(1);
}
- memcpy(&database_size, outbuf.data, sizeof(database_size));
+
+ retval = decode_database_size(&outbuf, &database_size);
+ if (retval) {
+ send_error(context, fd, retval, "malformed database size message");
+ com_err(progname, retval,
+ _("malformed database size message from client"));
+ exit(1);
+ }
+
krb5_free_data_contents(context, &inbuf);
krb5_free_data_contents(context, &outbuf);
- database_size = ntohl(database_size);
/* Initialize the initial vector. */
retval = krb5_auth_con_initivector(context, auth_context);
@@ -1401,7 +1410,7 @@ recv_database(krb5_context context, int fd, int database_fd,
retval = krb5_read_message(context, &fd, &inbuf);
if (retval) {
snprintf(buf, sizeof(buf),
- "while reading database block starting at offset %d",
+ "while reading database block starting at offset %"PRIu64,
received_size);
com_err(progname, retval, "%s", buf);
send_error(context, fd, retval, buf);
@@ -1412,8 +1421,8 @@ recv_database(krb5_context context, int fd, int database_fd,
retval = krb5_rd_priv(context, auth_context, &inbuf, &outbuf, NULL);
if (retval) {
snprintf(buf, sizeof(buf),
- "while decoding database block starting at offset %d",
- received_size);
+ "while decoding database block starting at offset %"
+ PRIu64, received_size);
com_err(progname, retval, "%s", buf);
send_error(context, fd, retval, buf);
krb5_free_data_contents(context, &inbuf);
@@ -1424,13 +1433,13 @@ recv_database(krb5_context context, int fd, int database_fd,
krb5_free_data_contents(context, &outbuf);
if (n < 0) {
snprintf(buf, sizeof(buf),
- "while writing database block starting at offset %d",
+ "while writing database block starting at offset %"PRIu64,
received_size);
send_error(context, fd, errno, buf);
} else if ((unsigned int)n != outbuf.length) {
snprintf(buf, sizeof(buf),
"incomplete write while writing database block starting "
- "at \noffset %d (%d written, %d expected)",
+ "at \noffset %"PRIu64" (%d written, %d expected)",
received_size, n, outbuf.length);
send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
}
@@ -1440,7 +1449,8 @@ recv_database(krb5_context context, int fd, int database_fd,
/* OK, we've seen the entire file. Did we get too many bytes? */
if (received_size > database_size) {
snprintf(buf, sizeof(buf),
- "Received %d bytes, expected %d bytes for database file",
+ "Received %"PRIu64" bytes, expected %"PRIu64
+ " bytes for database file",
received_size, database_size);
send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
}
@@ -1450,9 +1460,8 @@ recv_database(krb5_context context, int fd, int database_fd,
/* Create message acknowledging number of bytes received, but
* don't send it until kdb5_util returns successfully. */
- database_size = htonl(database_size);
- inbuf.data = (char *)&database_size;
- inbuf.length = sizeof(database_size);
+ inbuf = make_data(dbsize_buf, sizeof(dbsize_buf));
+ encode_database_size(database_size, &inbuf);
retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL);
if (retval) {
com_err(progname, retval, "while encoding # of receieved bytes");
diff --git a/src/tests/t_kprop.py b/src/tests/t_kprop.py
index c33e4fea2..f8ffd653a 100755
--- a/src/tests/t_kprop.py
+++ b/src/tests/t_kprop.py
@@ -87,5 +87,39 @@ realm.run([kdb5_util, 'dump', dumpfile])
realm.run([kprop, '-f', dumpfile, '-P', str(realm.kprop_port()), hostname])
check_output(kpropd)
realm.run([kadminl, 'listprincs'], replica3, expected_msg='wakawaka')
+stop_daemon(kpropd)
+
+# This test is too resource-intensive to be included in "make check"
+# by default, but it can be enabled in the environment to test the
+# propagation of databases large enough to require a 12-byte encoding
+# of the database size.
+if 'KPROP_LARGE_DB_TEST' in os.environ:
+ output('Generating >4GB dumpfile\n')
+ with open(dumpfile, 'w') as f:
+ f.write('kdb5_util load_dump version 6\n')
+ f.write('princ\t38\t15\t3\t1\t0\tK/M@KRBTEST.COM\t64\t86400\t0\t0\t0'
+ '\t0\t0\t0\t8\t2\t0100\t9\t8\t0100010000000000\t2\t28'
+ '\tb93e105164625f6372656174696f6e404b5242544553542e434f4d00'
+ '\t1\t1\t18\t62\t2000408c027c250e8cc3b81476414f2214d57c1ce'
+ '38891e29792e87258247c73547df4d5756266931dd6686b62270e6568'
+ '95a31ec66bfe913b4f15226227\t-1;\n')
+ for i in range(1, 20000000):
+ f.write('princ\t38\t21\t1\t1\t0\tp%08d@KRBTEST.COM' % i)
+ f.write('\t0\t86400\t0\t0\t0\t0\t0\t0\t2\t27'
+ '\td73e1051757365722f61646d696e404b5242544553542e434f4d00'
+ '\t1\t1\t17\t46'
+ '\t10009c8ab7b3f89ccf3ca3ad98352a461b7f4f1b0c49'
+ '5605117591d9ad52ba4da0adef7a902126973ed2bdc3ffbf\t-1;\n')
+ assert os.path.getsize(dumpfile) > 4 * 1024 * 1024 * 1024
+ with open(dumpfile + '.dump_ok', 'w') as f:
+ f.write('\0')
+ conf_large = {'dbmodules': {'db': {'database_name': '$testdir/db.large'}},
+ 'realms': {'$realm': {'iprop_resync_timeout': '3600'}}}
+ large = realm.special_env('large', True, kdc_conf=conf_large)
+ kpropd = realm.start_kpropd(large, ['-d'])
+ realm.run([kprop, '-f', dumpfile, '-P', str(realm.kprop_port()), hostname])
+ check_output(kpropd)
+ realm.run([kadminl, 'getprinc', 'p19999999'], env=large,
+ expected_msg='Principal: p19999999')
success('kprop tests')
--
2.35.1

@ -0,0 +1,49 @@
From f7b6d43533d1d9ec3960e3d7f375995896768aef Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 6 May 2020 16:03:13 -0400
Subject: [PATCH] Omit KDC indicator check for S4U2Self requests
As there was no initial ticket exchange from the client for an
S4U2Self request, the auth indicator check is inapplicable (and would
always fail if any auth indicators are required).
ticket: 8902 (new)
(cherry picked from commit 183631fbf72351c2d5fc7d60b2d9fc4d09fe7465)
(cherry picked from commit 442f1fa5b2e4034954a51048414cc0863b914379)
---
src/kdc/do_tgs_req.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 241f34e2a..463a9c0dd 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -392,8 +392,8 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
}
authtime = subject_tkt->times.authtime;
- /* Extract auth indicators from the subject ticket, except for S4U2Self
- * requests (where the client didn't authenticate). */
+ /* Extract and check auth indicators from the subject ticket, except for
+ * S4U2Self requests (where the client didn't authenticate). */
if (s4u_x509_user == NULL) {
errcode = get_auth_indicators(kdc_context, subject_tkt, local_tgt,
&local_tgt_key, &auth_indicators);
@@ -401,12 +401,12 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
status = "GET_AUTH_INDICATORS";
goto cleanup;
}
- }
- errcode = check_indicators(kdc_context, server, auth_indicators);
- if (errcode) {
- status = "HIGHER_AUTHENTICATION_REQUIRED";
- goto cleanup;
+ errcode = check_indicators(kdc_context, server, auth_indicators);
+ if (errcode) {
+ status = "HIGHER_AUTHENTICATION_REQUIRED";
+ goto cleanup;
+ }
}
if (is_referral)

@ -0,0 +1,35 @@
From e1b2c967266b14bc37e5ed11e6c0525bd259e0bb Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Sat, 6 Jun 2020 11:03:37 +0200
Subject: [PATCH] Omit PA_FOR_USER if we can't compute its checksum
OpenSSL in FIPS mode will refuse to perform hmac-md5. Omit the legacy
PA_FOR_USER element in this case rather than failing out.
[ghudson@mit.edu: minor code and comment edits; wrote commit message]
ticket: 8912 (new)
(cherry picked from commit 03f122bdb22cfa53c7d855ed929c9541e56365e0)
(cherry picked from commit 086de78292b8ae89aba8a72926831124da44205d)
---
src/lib/krb5/krb/s4u_creds.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/lib/krb5/krb/s4u_creds.c b/src/lib/krb5/krb/s4u_creds.c
index fc5c886d6..d8f486dc6 100644
--- a/src/lib/krb5/krb/s4u_creds.c
+++ b/src/lib/krb5/krb/s4u_creds.c
@@ -534,6 +534,13 @@ krb5_get_self_cred_from_kdc(krb5_context context,
if (s4u_user.user_id.user != NULL && s4u_user.user_id.user->length) {
code = build_pa_for_user(context, tgtptr, &s4u_user.user_id,
&in_padata[1]);
+ /*
+ * If we couldn't compute the hmac-md5 checksum, send only the
+ * KRB5_PADATA_S4U_X509_USER; this will still work against modern
+ * Windows and MIT KDCs.
+ */
+ if (code == KRB5_CRYPTO_INTERNAL)
+ code = 0;
if (code != 0) {
krb5_free_pa_data(context, in_padata);
goto cleanup;

@ -0,0 +1,257 @@
From 6265b0fbc59e13756364b97a5e3e8672514f8302 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Tue, 28 Apr 2020 18:15:55 +0200
Subject: [PATCH] Pass channel bindings through SPNEGO
ticket: 8907 (new)
(cherry picked from commit d16325a24c34ec9a5f6fb4910987f162e0d4d9cd)
(cherry picked from commit ee79bd43005245d3e5a2d3ec6d61146945e77717)
---
src/lib/gssapi/spnego/gssapiP_negoex.h | 8 ++---
src/lib/gssapi/spnego/negoex_ctx.c | 34 +++++++++++----------
src/lib/gssapi/spnego/spnego_mech.c | 41 +++++++++++++-------------
3 files changed, 43 insertions(+), 40 deletions(-)
diff --git a/src/lib/gssapi/spnego/gssapiP_negoex.h b/src/lib/gssapi/spnego/gssapiP_negoex.h
index 44b08f523..489ab7c42 100644
--- a/src/lib/gssapi/spnego/gssapiP_negoex.h
+++ b/src/lib/gssapi/spnego/gssapiP_negoex.h
@@ -201,10 +201,10 @@ negoex_restrict_auth_schemes(spnego_gss_ctx_id_t ctx,
OM_uint32
negoex_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
gss_name_t target_name, OM_uint32 req_flags, OM_uint32 time_req,
- gss_buffer_t input_token, gss_buffer_t output_token,
- OM_uint32 *time_rec);
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec);
OM_uint32
negoex_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
- gss_buffer_t input_token, gss_buffer_t output_token,
- OM_uint32 *time_rec);
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec);
diff --git a/src/lib/gssapi/spnego/negoex_ctx.c b/src/lib/gssapi/spnego/negoex_ctx.c
index 18d9d4147..8848ee4db 100644
--- a/src/lib/gssapi/spnego/negoex_ctx.c
+++ b/src/lib/gssapi/spnego/negoex_ctx.c
@@ -276,7 +276,8 @@ static OM_uint32
mech_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
gss_name_t target, OM_uint32 req_flags, OM_uint32 time_req,
struct negoex_message *messages, size_t nmessages,
- gss_buffer_t output_token, OM_uint32 *time_rec)
+ gss_channel_bindings_t bindings, gss_buffer_t output_token,
+ OM_uint32 *time_rec)
{
OM_uint32 major, first_major = 0, first_minor = 0;
struct negoex_auth_mech *mech = NULL;
@@ -316,10 +317,9 @@ mech_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
mech = K5_TAILQ_FIRST(&ctx->negoex_mechs);
major = gss_init_sec_context(minor, cred, &mech->mech_context, target,
- mech->oid, req_flags, time_req,
- GSS_C_NO_CHANNEL_BINDINGS, input_token,
- &ctx->actual_mech, output_token,
- &ctx->ctx_flags, time_rec);
+ mech->oid, req_flags, time_req, bindings,
+ input_token, &ctx->actual_mech,
+ output_token, &ctx->ctx_flags, time_rec);
if (major == GSS_S_COMPLETE)
mech->complete = 1;
@@ -351,7 +351,8 @@ mech_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
static OM_uint32
mech_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
gss_cred_id_t cred, struct negoex_message *messages,
- size_t nmessages, gss_buffer_t output_token, OM_uint32 *time_rec)
+ size_t nmessages, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec)
{
OM_uint32 major, tmpmin;
struct negoex_auth_mech *mech;
@@ -395,10 +396,10 @@ mech_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
gss_release_cred(&tmpmin, &ctx->deleg_cred);
major = gss_accept_sec_context(minor, &mech->mech_context, cred,
- &msg->token, GSS_C_NO_CHANNEL_BINDINGS,
- &ctx->internal_name, &ctx->actual_mech,
- output_token, &ctx->ctx_flags,
- time_rec, &ctx->deleg_cred);
+ &msg->token, bindings, &ctx->internal_name,
+ &ctx->actual_mech, output_token,
+ &ctx->ctx_flags, time_rec,
+ &ctx->deleg_cred);
if (major == GSS_S_COMPLETE)
mech->complete = 1;
@@ -609,8 +610,8 @@ make_output_token(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
OM_uint32
negoex_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
gss_name_t target_name, OM_uint32 req_flags, OM_uint32 time_req,
- gss_buffer_t input_token, gss_buffer_t output_token,
- OM_uint32 *time_rec)
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec)
{
OM_uint32 major, tmpmin;
gss_buffer_desc mech_output_token = GSS_C_EMPTY_BUFFER;
@@ -663,7 +664,8 @@ negoex_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
/* Process the input token and/or produce an output token. This may prune
* the mech list, but on success there will be at least one mech entry. */
major = mech_init(minor, ctx, cred, target_name, req_flags, time_req,
- messages, nmessages, &mech_output_token, time_rec);
+ messages, nmessages, bindings, &mech_output_token,
+ time_rec);
if (major != GSS_S_COMPLETE)
goto cleanup;
assert(!K5_TAILQ_EMPTY(&ctx->negoex_mechs));
@@ -701,8 +703,8 @@ cleanup:
OM_uint32
negoex_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
- gss_buffer_t input_token, gss_buffer_t output_token,
- OM_uint32 *time_rec)
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
+ gss_buffer_t output_token, OM_uint32 *time_rec)
{
OM_uint32 major, tmpmin;
gss_buffer_desc mech_output_token = GSS_C_EMPTY_BUFFER;
@@ -754,7 +756,7 @@ negoex_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
* prune the list to a single mech. Continue on error if an output token
* is generated, so that we send the token to the initiator.
*/
- major = mech_accept(minor, ctx, cred, messages, nmessages,
+ major = mech_accept(minor, ctx, cred, messages, nmessages, bindings,
&mech_output_token, time_rec);
if (major != GSS_S_COMPLETE && mech_output_token.length == 0)
goto cleanup;
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 594fc5894..4cf011143 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -130,6 +130,7 @@ init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
static OM_uint32
init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
OM_uint32, gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
+ gss_channel_bindings_t,
gss_buffer_t, OM_uint32 *, send_token_flag *);
static OM_uint32
@@ -144,8 +145,8 @@ acc_ctx_vfy_oid(OM_uint32 *, spnego_gss_ctx_id_t, gss_OID,
OM_uint32 *, send_token_flag *);
static OM_uint32
acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
- gss_buffer_t, gss_buffer_t, OM_uint32 *, OM_uint32 *,
- send_token_flag *);
+ gss_buffer_t, gss_channel_bindings_t, gss_buffer_t,
+ OM_uint32 *, OM_uint32 *, send_token_flag *);
static gss_OID
negotiate_mech(spnego_gss_ctx_id_t, gss_OID_set, OM_uint32 *);
@@ -905,6 +906,7 @@ init_ctx_call_init(OM_uint32 *minor_status,
OM_uint32 req_flags,
OM_uint32 time_req,
gss_buffer_t mechtok_in,
+ gss_channel_bindings_t bindings,
gss_buffer_t mechtok_out,
OM_uint32 *time_rec,
send_token_flag *send_token)
@@ -921,15 +923,14 @@ init_ctx_call_init(OM_uint32 *minor_status,
if (gss_oid_equal(sc->internal_mech, &negoex_mech)) {
ret = negoex_init(minor_status, sc, mcred, target_name,
mech_req_flags, time_req, mechtok_in,
- mechtok_out, time_rec);
+ bindings, mechtok_out, time_rec);
} else {
ret = gss_init_sec_context(minor_status, mcred,
&sc->ctx_handle, target_name,
sc->internal_mech, mech_req_flags,
- time_req, GSS_C_NO_CHANNEL_BINDINGS,
- mechtok_in, &sc->actual_mech,
- mechtok_out, &sc->ctx_flags,
- time_rec);
+ time_req, bindings, mechtok_in,
+ &sc->actual_mech, mechtok_out,
+ &sc->ctx_flags, time_rec);
}
/* Bail out if the acceptor gave us an error token but the mech didn't
@@ -981,8 +982,8 @@ init_ctx_call_init(OM_uint32 *minor_status,
gss_delete_sec_context(&tmpmin, &sc->ctx_handle, GSS_C_NO_BUFFER);
tmpret = init_ctx_call_init(&tmpmin, sc, spcred, acc_negState,
target_name, req_flags, time_req,
- mechtok_in, mechtok_out, time_rec,
- send_token);
+ mechtok_in, bindings, mechtok_out,
+ time_rec, send_token);
if (HARD_ERROR(tmpret))
goto fail;
*minor_status = tmpmin;
@@ -1004,7 +1005,7 @@ spnego_gss_init_sec_context(
gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
- gss_channel_bindings_t input_chan_bindings,
+ gss_channel_bindings_t bindings,
gss_buffer_t input_token,
gss_OID *actual_mech,
gss_buffer_t output_token,
@@ -1084,8 +1085,8 @@ spnego_gss_init_sec_context(
if (!spnego_ctx->mech_complete) {
ret = init_ctx_call_init(minor_status, spnego_ctx, spcred,
acc_negState, target_name, req_flags,
- time_req, mechtok_in, &mechtok_out,
- time_rec, &send_token);
+ time_req, mechtok_in, bindings,
+ &mechtok_out, time_rec, &send_token);
if (ret != GSS_S_COMPLETE)
goto cleanup;
@@ -1542,8 +1543,9 @@ cleanup:
static OM_uint32
acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
spnego_gss_cred_id_t spcred, gss_buffer_t mechtok_in,
- gss_buffer_t mechtok_out, OM_uint32 *time_rec,
- OM_uint32 *negState, send_token_flag *tokflag)
+ gss_channel_bindings_t bindings, gss_buffer_t mechtok_out,
+ OM_uint32 *time_rec, OM_uint32 *negState,
+ send_token_flag *tokflag)
{
OM_uint32 ret, tmpmin;
gss_OID_desc mechoid;
@@ -1568,13 +1570,12 @@ acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
if (negoex) {
ret = negoex_accept(minor_status, sc, mcred, mechtok_in,
- mechtok_out, time_rec);
+ bindings, mechtok_out, time_rec);
} else {
(void) gss_release_name(&tmpmin, &sc->internal_name);
(void) gss_release_cred(&tmpmin, &sc->deleg_cred);
ret = gss_accept_sec_context(minor_status, &sc->ctx_handle,
- mcred, mechtok_in,
- GSS_C_NO_CHANNEL_BINDINGS,
+ mcred, mechtok_in, bindings,
&sc->internal_name,
&sc->actual_mech, mechtok_out,
&sc->ctx_flags, time_rec,
@@ -1620,7 +1621,7 @@ spnego_gss_accept_sec_context(
gss_ctx_id_t *context_handle,
gss_cred_id_t verifier_cred_handle,
gss_buffer_t input_token,
- gss_channel_bindings_t input_chan_bindings,
+ gss_channel_bindings_t bindings,
gss_name_t *src_name,
gss_OID *mech_type,
gss_buffer_t output_token,
@@ -1734,8 +1735,8 @@ spnego_gss_accept_sec_context(
*/
if (negState != REQUEST_MIC && mechtok_in != GSS_C_NO_BUFFER) {
ret = acc_ctx_call_acc(minor_status, sc, spcred, mechtok_in,
- &mechtok_out, time_rec, &negState,
- &return_token);
+ bindings, &mechtok_out, time_rec,
+ &negState, &return_token);
}
/* Step 3: process or generate the MIC, if the negotiated mech is

@ -0,0 +1,59 @@
From e57cdf6610f0b7c8ac38f9b2342b74b8c9e5bc54 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sun, 26 Apr 2020 19:55:54 -0400
Subject: [PATCH] Pass gss_localname() through SPNEGO
ticket: 8897 (new)
(cherry picked from commit f7b8a6432bd289bdc528017be122305f95b8e285)
(cherry picked from commit 646212314a580a8cdffdacda9cb3c8f806471b08)
---
src/lib/gssapi/spnego/gssapiP_spnego.h | 8 ++++++++
src/lib/gssapi/spnego/spnego_mech.c | 9 ++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h
index a93763314..066ec736f 100644
--- a/src/lib/gssapi/spnego/gssapiP_spnego.h
+++ b/src/lib/gssapi/spnego/gssapiP_spnego.h
@@ -357,6 +357,14 @@ OM_uint32 KRB5_CALLCONV spnego_gss_wrap_size_limit
OM_uint32 *max_input_size
);
+OM_uint32 KRB5_CALLCONV spnego_gss_localname
+(
+ OM_uint32 *minor_status,
+ const gss_name_t pname,
+ const gss_const_OID mech_type,
+ gss_buffer_t localname
+);
+
OM_uint32 KRB5_CALLCONV spnego_gss_get_mic
(
OM_uint32 *minor_status,
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index ec0bae6a4..594fc5894 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -237,7 +237,7 @@ static struct gss_config spnego_mechanism =
spnego_gss_inquire_context, /* gss_inquire_context */
NULL, /* gss_internal_release_oid */
spnego_gss_wrap_size_limit, /* gss_wrap_size_limit */
- NULL, /* gssd_pname_to_uid */
+ spnego_gss_localname,
NULL, /* gss_userok */
NULL, /* gss_export_name */
spnego_gss_duplicate_name, /* gss_duplicate_name */
@@ -2371,6 +2371,13 @@ spnego_gss_wrap_size_limit(
return (ret);
}
+OM_uint32 KRB5_CALLCONV
+spnego_gss_localname(OM_uint32 *minor_status, const gss_name_t pname,
+ const gss_const_OID mech_type, gss_buffer_t localname)
+{
+ return gss_localname(minor_status, pname, GSS_C_NO_OID, localname);
+}
+
OM_uint32 KRB5_CALLCONV
spnego_gss_get_mic(
OM_uint32 *minor_status,

@ -0,0 +1,480 @@
From 4f14a2f48b52e59c472847a5522fd0cf52927755 Mon Sep 17 00:00:00 2001
From: Alexander Scheel <ascheel@redhat.com>
Date: Fri, 30 Jun 2017 16:03:01 -0400
Subject: [PATCH] Refactor krb5 GSS checksum handling
Separate out checksum handling from kg_accept_krb5() into a new helper
process_checksum().
[ghudson@mit.edu: simplified checksum processing and made it use
k5-input.h instead of TREAD_ macros; moved more flag handling into
helper]
[iboukris: adjusted helper function arguments, allowing access to the
full authenticator for subsequent changes]
(cherry picked from commit 64d56233f9816a2a93f6e8d3030c8ed6ce397735)
[rharwood@redhat.com: problem with typo fix commit, I think]
(cherry picked from commit a34b7c50e62c19f80d39ece6a72017dac781df64)
---
src/lib/gssapi/krb5/accept_sec_context.c | 383 +++++++++++------------
1 file changed, 179 insertions(+), 204 deletions(-)
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index c5bddb1e8..70dd7fc0c 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -98,6 +98,7 @@
*/
#include "k5-int.h"
+#include "k5-input.h"
#include "gssapiP_krb5.h"
#ifdef HAVE_MEMORY_H
#include <memory.h>
@@ -413,6 +414,174 @@ kg_process_extension(krb5_context context,
return code;
}
+/* The length of the MD5 channel bindings in an 0x8003 checksum */
+#define CB_MD5_LEN 16
+
+/* The minimum length of an 0x8003 checksum value (4-byte channel bindings
+ * length, 16-byte channel bindings, 4-byte flags) */
+#define MIN_8003_LEN (4 + CB_MD5_LEN + 4)
+
+/* The flags we accept from the initiator's authenticator checksum. */
+#define INITIATOR_FLAGS (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG | \
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | \
+ GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE | \
+ GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG)
+
+/*
+ * The krb5 GSS mech appropriates the authenticator checksum field from RFC
+ * 4120 to store structured data instead of a checksum, indicated with checksum
+ * type 0x8003 (see RFC 4121 section 4.1.1). Some implementations instead send
+ * no checksum, or a regular checksum over empty data.
+ *
+ * Interpret the checksum. Read delegated creds into *deleg_out if it is not
+ * NULL. Set *flags_out to the allowed subset of token flags, plus
+ * GSS_C_DELEG_FLAG if a delegated credential was present. Process any
+ * extensions found using exts. On error, set *code_out to a krb5_error code
+ * for use as a minor status value.
+ */
+static OM_uint32
+process_checksum(OM_uint32 *minor_status, krb5_context context,
+ gss_channel_bindings_t acceptor_cb,
+ krb5_auth_context auth_context, krb5_flags ap_req_options,
+ krb5_authenticator *authenticator, krb5_gss_ctx_ext_t exts,
+ krb5_gss_cred_id_t *deleg_out, krb5_ui_4 *flags_out,
+ krb5_error_code *code_out)
+{
+ krb5_error_code code = 0;
+ OM_uint32 status, option_id, token_flags;
+ size_t cb_len, option_len;
+ krb5_boolean valid;
+ krb5_key subkey;
+ krb5_data option, empty = empty_data();
+ krb5_checksum cb_cksum;
+ const uint8_t *token_cb, *option_bytes;
+ struct k5input in;
+ const krb5_checksum *cksum = authenticator->checksum;
+
+ cb_cksum.contents = NULL;
+
+ if (cksum == NULL) {
+ /*
+ * Some SMB client implementations use handcrafted GSSAPI code that
+ * does not provide a checksum. MS-KILE documents that the Microsoft
+ * implementation considers a missing checksum acceptable; the server
+ * assumes all flags are unset in this case, and does not check channel
+ * bindings.
+ */
+ *flags_out = 0;
+ } else if (cksum->checksum_type != CKSUMTYPE_KG_CB) {
+ /* Samba sends a regular checksum. */
+ code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
+ if (code) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* Verifying the checksum ensures that this authenticator wasn't
+ * replayed from one with a checksum over actual data. */
+ code = krb5_k_verify_checksum(context, subkey,
+ KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM, &empty,
+ cksum, &valid);
+ krb5_k_free_key(context, subkey);
+ if (code || !valid) {
+ status = GSS_S_BAD_SIG;
+ goto fail;
+ }
+
+ /* Use ap_options from the request to guess the mutual flag. */
+ *flags_out = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
+ if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
+ *flags_out |= GSS_C_MUTUAL_FLAG;
+ } else {
+ /* The checksum must contain at least a fixed 24-byte part. */
+ if (cksum->length < MIN_8003_LEN) {
+ status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+
+ k5_input_init(&in, cksum->contents, cksum->length);
+ cb_len = k5_input_get_uint32_le(&in);
+ if (cb_len != CB_MD5_LEN) {
+ code = KG_BAD_LENGTH;
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ token_cb = k5_input_get_bytes(&in, cb_len);
+ if (acceptor_cb != GSS_C_NO_CHANNEL_BINDINGS) {
+ code = kg_checksum_channel_bindings(context, acceptor_cb,
+ &cb_cksum);
+ if (code) {
+ status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+ assert(cb_cksum.length == cb_len);
+ if (k5_bcmp(token_cb, cb_cksum.contents, cb_len) != 0) {
+ status = GSS_S_BAD_BINDINGS;
+ goto fail;
+ }
+ }
+
+ /* Read the token flags and accept some of them as context flags. */
+ token_flags = k5_input_get_uint32_le(&in);
+ *flags_out = token_flags & INITIATOR_FLAGS;
+
+ /* Read the delegated credential if present. */
+ if (in.len >= 4 && (token_flags & GSS_C_DELEG_FLAG)) {
+ option_id = k5_input_get_uint16_le(&in);
+ option_len = k5_input_get_uint16_le(&in);
+ option_bytes = k5_input_get_bytes(&in, option_len);
+ option = make_data((uint8_t *)option_bytes, option_len);
+ if (in.status) {
+ code = KG_BAD_LENGTH;
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+ if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ /* Store the delegated credential. */
+ code = rd_and_store_for_creds(context, auth_context, &option,
+ deleg_out);
+ if (code) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+ *flags_out |= GSS_C_DELEG_FLAG;
+ }
+
+ /* Process any extensions at the end of the checksum. Extensions use
+ * 4-byte big-endian tag and length instead of 2-byte little-endian. */
+ while (in.len > 0) {
+ option_id = k5_input_get_uint32_be(&in);
+ option_len = k5_input_get_uint32_be(&in);
+ option_bytes = k5_input_get_bytes(&in, option_len);
+ option = make_data((uint8_t *)option_bytes, option_len);
+ if (in.status) {
+ code = KG_BAD_LENGTH;
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+
+ code = kg_process_extension(context, auth_context, option_id,
+ &option, exts);
+ if (code) {
+ status = GSS_S_FAILURE;
+ goto fail;
+ }
+ }
+ }
+
+ status = GSS_S_COMPLETE;
+
+fail:
+ free(cb_cksum.contents);
+ *code_out = code;
+ return status;
+}
+
static OM_uint32
kg_accept_krb5(minor_status, context_handle,
verifier_cred_handle, input_token,
@@ -433,17 +602,13 @@ kg_accept_krb5(minor_status, context_handle,
krb5_gss_ctx_ext_t exts;
{
krb5_context context;
- unsigned char *ptr, *ptr2;
+ unsigned char *ptr;
char *sptr;
- OM_uint32 tmp;
- size_t md5len;
krb5_gss_cred_id_t cred = 0;
krb5_data ap_rep, ap_req;
- unsigned int i;
krb5_error_code code;
krb5_address addr, *paddr;
krb5_authenticator *authdat = 0;
- krb5_checksum reqcksum;
krb5_gss_name_t name = NULL;
krb5_ui_4 gss_flags = 0;
krb5_gss_ctx_id_rec *ctx = NULL;
@@ -451,8 +616,6 @@ kg_accept_krb5(minor_status, context_handle,
gss_buffer_desc token;
krb5_auth_context auth_context = NULL;
krb5_ticket * ticket = NULL;
- int option_id;
- krb5_data option;
const gss_OID_desc *mech_used = NULL;
OM_uint32 major_status = GSS_S_FAILURE;
OM_uint32 tmp_minor_status;
@@ -463,7 +626,6 @@ kg_accept_krb5(minor_status, context_handle,
krb5int_access kaccess;
int cred_rcache = 0;
int no_encap = 0;
- int token_deleg_flag = 0;
krb5_flags ap_req_options = 0;
krb5_enctype negotiated_etype;
krb5_authdata_context ad_context = NULL;
@@ -489,7 +651,6 @@ kg_accept_krb5(minor_status, context_handle,
output_token->length = 0;
output_token->value = NULL;
token.value = 0;
- reqcksum.contents = 0;
ap_req.data = 0;
ap_rep.data = 0;
@@ -654,195 +815,16 @@ kg_accept_krb5(minor_status, context_handle,
krb5_auth_con_getauthenticator(context, auth_context, &authdat);
- if (authdat->checksum == NULL) {
- /*
- * Some SMB client implementations use handcrafted GSSAPI code that
- * does not provide a checksum. MS-KILE documents that the Microsoft
- * implementation considers a missing checksum acceptable; the server
- * assumes all flags are unset in this case, and does not check channel
- * bindings.
- */
- gss_flags = 0;
- } else if (authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) {
- /* Samba does not send 0x8003 GSS-API checksums */
- krb5_boolean valid;
- krb5_key subkey;
- krb5_data zero;
+ major_status = process_checksum(minor_status, context, input_chan_bindings,
+ auth_context, ap_req_options,
+ authdat, exts,
+ delegated_cred_handle ? &deleg_cred : NULL,
+ &gss_flags, &code);
- code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
- if (code) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
+ if (major_status != GSS_S_COMPLETE)
+ goto fail;
- zero.length = 0;
- zero.data = "";
-
- code = krb5_k_verify_checksum(context,
- subkey,
- KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
- &zero,
- authdat->checksum,
- &valid);
- krb5_k_free_key(context, subkey);
- if (code || !valid) {
- major_status = GSS_S_BAD_SIG;
- goto fail;
- }
-
- /* Use ap_options from the request to guess the mutual flag. */
- gss_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
- if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
- gss_flags |= GSS_C_MUTUAL_FLAG;
- } else {
- /* gss krb5 v1 */
-
- /* stash this now, for later. */
- code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
- if (code) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- /* verify that the checksum is correct */
-
- /*
- The checksum may be either exactly 24 bytes, in which case
- no options are specified, or greater than 24 bytes, in which case
- one or more options are specified. Currently, the only valid
- option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
- */
-
- if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
- (authdat->checksum->length < 24)) {
- code = 0;
- major_status = GSS_S_BAD_BINDINGS;
- goto fail;
- }
-
- ptr = (unsigned char *) authdat->checksum->contents;
-
- TREAD_INT(ptr, tmp, 0);
-
- if (tmp != md5len) {
- code = KG_BAD_LENGTH;
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- /*
- The following section of code attempts to implement the
- optional channel binding facility as described in RFC2743.
-
- Since this facility is optional channel binding may or may
- not have been provided by either the client or the server.
-
- If the server has specified input_chan_bindings equal to
- GSS_C_NO_CHANNEL_BINDINGS then we skip the check. If
- the server does provide channel bindings then we compute
- a checksum and compare against those provided by the
- client. */
-
- if ((code = kg_checksum_channel_bindings(context,
- input_chan_bindings,
- &reqcksum))) {
- major_status = GSS_S_BAD_BINDINGS;
- goto fail;
- }
-
- /* Always read the clients bindings - eventhough we might ignore them */
- TREAD_STR(ptr, ptr2, reqcksum.length);
-
- if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
- if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
- xfree(reqcksum.contents);
- reqcksum.contents = 0;
- code = 0;
- major_status = GSS_S_BAD_BINDINGS;
- goto fail;
- }
-
- }
-
- xfree(reqcksum.contents);
- reqcksum.contents = 0;
-
- /* Read the token flags. Remember if GSS_C_DELEG_FLAG was set, but
- * mask it out until we actually read a delegated credential. */
- TREAD_INT(ptr, gss_flags, 0);
- token_deleg_flag = (gss_flags & GSS_C_DELEG_FLAG);
- gss_flags &= ~GSS_C_DELEG_FLAG;
-
- /* if the checksum length > 24, there are options to process */
-
- i = authdat->checksum->length - 24;
- if (i && token_deleg_flag) {
- if (i >= 4) {
- TREAD_INT16(ptr, option_id, 0);
- TREAD_INT16(ptr, option.length, 0);
- i -= 4;
-
- if (i < option.length) {
- code = KG_BAD_LENGTH;
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- /* have to use ptr2, since option.data is wrong type and
- macro uses ptr as both lvalue and rvalue */
-
- TREAD_STR(ptr, ptr2, option.length);
- option.data = (char *) ptr2;
-
- i -= option.length;
-
- if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- /* store the delegated credential */
-
- code = rd_and_store_for_creds(context, auth_context, &option,
- (delegated_cred_handle) ?
- &deleg_cred : NULL);
- if (code) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
-
- gss_flags |= GSS_C_DELEG_FLAG;
- } /* if i >= 4 */
- /* ignore any additional trailing data, for now */
- }
- while (i > 0) {
- /* Process Type-Length-Data options */
- if (i < 8) {
- code = KG_BAD_LENGTH;
- major_status = GSS_S_FAILURE;
- goto fail;
- }
- TREAD_INT(ptr, option_id, 1);
- TREAD_INT(ptr, option.length, 1);
- i -= 8;
- if (i < option.length) {
- code = KG_BAD_LENGTH;
- major_status = GSS_S_FAILURE;
- goto fail;
- }
- TREAD_STR(ptr, ptr2, option.length);
- option.data = (char *)ptr2;
-
- i -= option.length;
-
- code = kg_process_extension(context, auth_context,
- option_id, &option, exts);
- if (code != 0) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
- }
- }
+ major_status = GSS_S_FAILURE;
if (exts->iakerb.conv && !exts->iakerb.verified) {
major_status = GSS_S_BAD_SIG;
@@ -869,12 +851,7 @@ kg_accept_krb5(minor_status, context_handle,
ctx->mech_used = (gss_OID) mech_used;
ctx->auth_context = auth_context;
ctx->initiate = 0;
- ctx->gss_flags = (GSS_C_TRANS_FLAG |
- ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
- GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
- GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
- GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
- GSS_C_EXTENDED_ERROR_FLAG)));
+ ctx->gss_flags = gss_flags | GSS_C_TRANS_FLAG;
ctx->seed_init = 0;
ctx->cred_rcache = cred_rcache;
@@ -1161,8 +1138,6 @@ fail:
krb5_auth_con_free(context, auth_context);
}
- if (reqcksum.contents)
- xfree(reqcksum.contents);
if (ap_rep.data)
krb5_free_data_contents(context, &ap_rep);
if (major_status == GSS_S_COMPLETE ||

@ -0,0 +1,79 @@
From cb8c8af56d306267d6964da217c65e129fe83c82 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Wed, 26 Feb 2020 18:27:17 -0500
Subject: [PATCH] Refresh manually acquired creds from client keytab
If a client keytab is present but credentials are acquired manually,
the credentials would not be refreshed because no refresh_time config
var is set in the cache. Change kg_cred_time_to_refresh() to attempt
a refresh from the client keytab on any credentials which will expire
in the next 30 seconds.
[ghudson@mit.edu: adjused code and added test case]
ticket: 7976
(cherry picked from commit 729896467e3c77904666019d6cbbda583ae49b95)
(cherry picked from commit 685aada9eae420cb5156ca7b71c2c7614c0b6e2c)
---
src/lib/gssapi/krb5/acquire_cred.c | 14 +++++++++++---
src/tests/gssapi/t_client_keytab.py | 18 ++++++++++++++++++
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index acc1868f8..4062f4741 100644
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -557,15 +557,23 @@ set_refresh_time(krb5_context context, krb5_ccache ccache,
krb5_boolean
kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred)
{
- krb5_timestamp now;
+ krb5_timestamp now, soon;
if (krb5_timeofday(context, &now))
return FALSE;
+ soon = ts_incr(now, 30);
if (cred->refresh_time != 0 && !ts_after(cred->refresh_time, now)) {
- set_refresh_time(context, cred->ccache,
- ts_incr(cred->refresh_time, 30));
+ set_refresh_time(context, cred->ccache, soon);
return TRUE;
}
+
+ /* If the creds will expire soon, try to refresh even if they weren't
+ * acquired with a client keytab. */
+ if (ts_after(soon, cred->expire)) {
+ set_refresh_time(context, cred->ccache, soon);
+ return TRUE;
+ }
+
return FALSE;
}
diff --git a/src/tests/gssapi/t_client_keytab.py b/src/tests/gssapi/t_client_keytab.py
index e474a27c7..7847b3ecd 100755
--- a/src/tests/gssapi/t_client_keytab.py
+++ b/src/tests/gssapi/t_client_keytab.py
@@ -124,4 +124,22 @@ realm.kinit(realm.user_princ, password('user'))
realm.run(['./t_ccselect', phost], env=bad_cktname,
expected_msg=realm.user_princ)
+mark('refresh of manually acquired creds')
+
+# Test 17: no name/ccache specified, manually acquired creds which
+# will expire soon. Verify that creds are refreshed using the current
+# client name, with refresh_time set in the refreshed ccache.
+realm.kinit('bob', password('bob'), ['-l', '15s'])
+realm.run(['./t_ccselect', phost], expected_msg='bob')
+realm.run([klist, '-C'], expected_msg='refresh_time = ')
+
+# Test 18: no name/ccache specified, manually acquired creds with a
+# client principal not present in the client keytab. A refresh is
+# attempted but fails, and an expired ticket error results.
+realm.kinit(realm.admin_princ, password('admin'), ['-l', '-1s'])
+msgs = ('Getting initial credentials for user/admin@KRBTEST.COM',
+ '/Matching credential not found')
+realm.run(['./t_ccselect', phost], expected_code=1,
+ expected_msg='Ticket expired', expected_trace=msgs)
+
success('Client keytab tests')

@ -1,4 +1,4 @@
From c52dea4944820750bf5881891bd92d6f5c7a73c4 Mon Sep 17 00:00:00 2001
From cc31e37cc4f8bbac99ee7eff37e8c25d21343bb7 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sun, 26 Nov 2023 17:42:34 -0500
Subject: [PATCH] Remove PKINIT RSA support
@ -11,21 +11,21 @@ ticket: 9108 (new)
---
doc/user/user_commands/kinit.rst | 4 -
src/plugins/preauth/pkinit/pkinit.h | 2 -
src/plugins/preauth/pkinit/pkinit_clnt.c | 235 +++-----
src/plugins/preauth/pkinit/pkinit_crypto.h | 39 --
.../preauth/pkinit/pkinit_crypto_openssl.c | 502 ------------------
src/plugins/preauth/pkinit/pkinit_clnt.c | 242 +++------
src/plugins/preauth/pkinit/pkinit_crypto.h | 42 --
.../preauth/pkinit/pkinit_crypto_openssl.c | 487 ------------------
src/plugins/preauth/pkinit/pkinit_lib.c | 2 -
src/plugins/preauth/pkinit/pkinit_srv.c | 208 +++-----
src/plugins/preauth/pkinit/pkinit_srv.c | 213 +++-----
src/plugins/preauth/pkinit/pkinit_trace.h | 9 -
src/tests/t_pkinit.py | 7 -
src/tests/t_pkinit.py | 9 -
src/windows/leash/htmlhelp/html/KINIT.htm | 3 -
10 files changed, 131 insertions(+), 880 deletions(-)
10 files changed, 139 insertions(+), 874 deletions(-)
diff --git a/doc/user/user_commands/kinit.rst b/doc/user/user_commands/kinit.rst
index 5b105e35a5..d947e83cc6 100644
index e12e88a372..2d67698dac 100644
--- a/doc/user/user_commands/kinit.rst
+++ b/doc/user/user_commands/kinit.rst
@@ -193,10 +193,6 @@ OPTIONS
@@ -192,10 +192,6 @@ OPTIONS
**X509_anchors**\ =\ *value*
specify where to find trusted X509 anchor information
@ -37,10 +37,10 @@ index 5b105e35a5..d947e83cc6 100644
disable sending freshness tokens (for testing purposes only)
diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
index 66f92d8f03..5ab0f4bc28 100644
index b437fd53fb..ab132d78a9 100644
--- a/src/plugins/preauth/pkinit/pkinit.h
+++ b/src/plugins/preauth/pkinit/pkinit.h
@@ -146,7 +146,6 @@ typedef struct _pkinit_plg_opts {
@@ -147,7 +147,6 @@ typedef struct _pkinit_plg_opts {
int require_eku; /* require EKU checking (default is true) */
int accept_secondary_eku;/* accept secondary EKU (default is false) */
int allow_upn; /* allow UPN-SAN instead of pkinit-SAN */
@ -48,7 +48,7 @@ index 66f92d8f03..5ab0f4bc28 100644
int require_crl_checking; /* require CRL for a CA (default is false) */
int require_freshness; /* require freshness token (default is false) */
int disable_freshness; /* disable freshness token on client for testing */
@@ -160,7 +159,6 @@ typedef struct _pkinit_req_opts {
@@ -161,7 +160,6 @@ typedef struct _pkinit_req_opts {
int require_eku;
int accept_secondary_eku;
int allow_upn;
@ -57,55 +57,65 @@ index 66f92d8f03..5ab0f4bc28 100644
int dh_size; /* initial request DH modulus size (default=1024) */
int require_hostname_match;
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index ea9ba454df..54e7537600 100644
index 021e5f0723..ca0162897b 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -191,7 +191,6 @@ pkinit_as_req_create(krb5_context context,
@@ -193,7 +193,6 @@ pkinit_as_req_create(krb5_context context,
krb5_auth_pack auth_pack;
krb5_pa_pk_as_req *req = NULL;
krb5_algorithm_identifier **cmstypes = NULL;
- int protocol = reqctx->opts->dh_or_rsa;
unsigned char *dh_params = NULL, *dh_pubkey = NULL;
unsigned int dh_params_len, dh_pubkey_len;
pkiDebug("pkinit_as_req_create pa_type = %d\n", reqctx->pa_type);
@@ -214,29 +213,14 @@ pkinit_as_req_create(krb5_context context,
if (retval)
goto cleanup;
@@ -212,35 +211,19 @@ pkinit_as_req_create(krb5_context context,
auth_pack.clientPublicValue = &info;
auth_pack.supportedKDFs = (krb5_data **)supported_kdf_alg_ids;
- switch(protocol) {
- case DH_PROTOCOL:
- TRACE_PKINIT_CLIENT_REQ_DH(context);
- pkiDebug("as_req: DH key transport algorithm\n");
+ TRACE_PKINIT_CLIENT_REQ_DH(context);
- info.algorithm.algorithm = dh_oid;
-
- /* create client-side DH keys */
- retval = client_create_dh(context, plgctx->cryptoctx,
- reqctx->cryptoctx, reqctx->idctx,
- reqctx->opts->dh_size, &spki);
- auth_pack.clientPublicValue = spki;
- reqctx->opts->dh_size, &dh_params,
- &dh_params_len, &dh_pubkey, &dh_pubkey_len);
- if (retval != 0) {
- pkiDebug("failed to create dh parameters\n");
- goto cleanup;
- }
- info.algorithm.parameters = make_data(dh_params, dh_params_len);
- info.subjectPublicKey = make_data(dh_pubkey, dh_pubkey_len);
- break;
- case RSA_PROTOCOL:
- TRACE_PKINIT_CLIENT_REQ_RSA(context);
- pkiDebug("as_req: RSA key transport algorithm\n");
- auth_pack.clientPublicValue = NULL;
- break;
- default:
- pkiDebug("as_req: unknown key transport protocol %d\n",
- protocol);
- retval = -1;
+ TRACE_PKINIT_CLIENT_REQ_DH(context);
+ info.algorithm.algorithm = dh_oid;
+
+ /* create client-side DH keys */
+ retval = client_create_dh(context, plgctx->cryptoctx, reqctx->cryptoctx,
+ reqctx->idctx, reqctx->opts->dh_size, &spki);
+ auth_pack.clientPublicValue = spki;
+ reqctx->idctx, reqctx->opts->dh_size, &dh_params,
+ &dh_params_len, &dh_pubkey, &dh_pubkey_len);
+ if (retval != 0) {
+ pkiDebug("failed to create dh parameters\n");
goto cleanup;
}
+ info.algorithm.parameters = make_data(dh_params, dh_params_len);
+ info.subjectPublicKey = make_data(dh_pubkey, dh_pubkey_len);
@@ -553,49 +537,34 @@ pkinit_as_rep_parse(krb5_context context,
retval = k5int_encode_krb5_auth_pack(&auth_pack, &coded_auth_pack);
if (retval) {
@@ -556,49 +539,33 @@ pkinit_as_rep_parse(krb5_context context,
return retval;
}
@ -159,17 +169,16 @@ index ea9ba454df..54e7537600 100644
- default:
- pkiDebug("unknown as_rep type %d\n", kdc_reply->choice);
- retval = -1;
+ retval = cms_signeddata_verify(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, reqctx->idctx,
+ CMS_SIGN_SERVER,
+ reqctx->opts->require_crl_checking,
+ (unsigned char *)
+ kdc_reply->u.dh_Info.dhSignedData.data,
+ kdc_reply->u.dh_Info.dhSignedData.length,
+ (unsigned char **)&dh_data.data,
+ &dh_data.length,
+ NULL, NULL, NULL);
+ if (retval) {
+ if ((retval = cms_signeddata_verify(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, reqctx->idctx,
+ CMS_SIGN_SERVER,
+ reqctx->opts->require_crl_checking,
+ (unsigned char *)
+ kdc_reply->u.dh_Info.dhSignedData.data,
+ kdc_reply->u.dh_Info.dhSignedData.length,
+ (unsigned char **)&dh_data.data,
+ &dh_data.length,
+ NULL, NULL, NULL)) != 0) {
+ pkiDebug("failed to verify pkcs7 signed data\n");
+ TRACE_PKINIT_CLIENT_REP_DH_FAIL(context);
goto cleanup;
@ -179,7 +188,7 @@ index ea9ba454df..54e7537600 100644
retval = krb5_build_principal_ext(context, &kdc_princ,
request->server->realm.length,
request->server->realm.data,
@@ -632,116 +601,54 @@ pkinit_as_rep_parse(krb5_context context,
@@ -635,116 +602,55 @@ pkinit_as_rep_parse(krb5_context context,
OCTETDATA_TO_KRB5DATA(&dh_data, &k5data);
@ -217,7 +226,11 @@ index ea9ba454df..54e7537600 100644
- request->client, request->server,
- etype, encoded_request,
- (krb5_data *)as_rep, key_block);
-
+ if ((retval = k5int_decode_krb5_kdc_dh_key_info(&k5data, &kdc_dh)) != 0) {
+ pkiDebug("failed to decode kdc_dh_key_info\n");
+ goto cleanup;
+ }
- if (retval) {
- pkiDebug("failed to create key pkinit_alg_agility_kdf %s\n",
- error_message(retval));
@ -225,24 +238,23 @@ index ea9ba454df..54e7537600 100644
- }
- TRACE_PKINIT_CLIENT_KDF_ALG(context, kdc_reply->u.dh_Info.kdfID,
- key_block);
+ retval = k5int_decode_krb5_kdc_dh_key_info(&k5data, &kdc_dh);
+ if (retval) {
+ pkiDebug("failed to decode kdc_dh_key_info\n");
+ /* client after KDC reply */
+ if ((retval = client_process_dh(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, reqctx->idctx,
+ (unsigned char *)
+ kdc_dh->subjectPublicKey.data,
+ kdc_dh->subjectPublicKey.length,
+ &client_key, &client_key_len)) != 0) {
+ pkiDebug("failed to process dh params\n");
+ goto cleanup;
+ }
- /* ...otherwise, use the older octetstring2key function. */
- } else {
+ /* client after KDC reply */
+ retval = client_process_dh(context, plgctx->cryptoctx, reqctx->cryptoctx,
+ reqctx->idctx,
+ (unsigned char *)kdc_dh->subjectPublicKey.data,
+ kdc_dh->subjectPublicKey.length, &client_key,
+ &client_key_len);
+ if (retval) {
+ pkiDebug("failed to process dh params\n");
+ goto cleanup;
+ }
+ /* If we have a KDF algorithm ID, call the algorithm agility KDF... */
+ if (kdc_reply->u.dh_Info.kdfID) {
+ secret.length = client_key_len;
+ secret.data = (char *)client_key;
- retval = pkinit_octetstring2key(context, etype, client_key,
- client_key_len, key_block);
@ -253,10 +265,11 @@ index ea9ba454df..54e7537600 100644
- }
- TRACE_PKINIT_CLIENT_KDF_OS2K(context, key_block);
- }
+ /* If we have a KDF algorithm ID, call the algorithm agility KDF. */
+ if (kdc_reply->u.dh_Info.kdfID) {
+ secret.length = client_key_len;
+ secret.data = (char *)client_key;
+ retval = pkinit_alg_agility_kdf(context, &secret,
+ kdc_reply->u.dh_Info.kdfID,
+ request->client, request->server,
+ etype, encoded_request,
+ (krb5_data *)as_rep, key_block);
- break;
- case choice_pa_pk_as_rep_encKeyPack:
@ -265,11 +278,6 @@ index ea9ba454df..54e7537600 100644
- "/tmp/client_key_pack");
-#endif
- retval = k5int_decode_krb5_reply_key_pack(&k5data, &key_pack);
+ retval = pkinit_alg_agility_kdf(context, &secret,
+ kdc_reply->u.dh_Info.kdfID,
+ request->client, request->server,
+ etype, encoded_request,
+ (krb5_data *)as_rep, key_block);
if (retval) {
- pkiDebug("failed to decode reply_key_pack\n");
+ pkiDebug("failed to create key pkinit_alg_agility_kdf %s\n",
@ -284,8 +292,9 @@ index ea9ba454df..54e7537600 100644
+ TRACE_PKINIT_CLIENT_KDF_ALG(context, kdc_reply->u.dh_Info.kdfID,
+ key_block);
+
+ /* ...otherwise, use the older octetstring2key function. */
+ } else {
+ /* Otherwise, use the older octetstring2key function. */
+
+ retval = pkinit_octetstring2key(context, etype, client_key,
+ client_key_len, key_block);
if (retval) {
@ -327,13 +336,13 @@ index ea9ba454df..54e7537600 100644
-
- break;
- default:
- pkiDebug("unknown as_rep type %d\n", kdc_reply->choice);
- pkiDebug("unknow as_rep type %d\n", kdc_reply->choice);
- goto cleanup;
+ TRACE_PKINIT_CLIENT_KDF_OS2K(context, key_block);
}
retval = 0;
@@ -1286,7 +1193,6 @@ pkinit_client_req_init(krb5_context context,
@@ -1286,7 +1192,6 @@ pkinit_client_req_init(krb5_context context,
reqctx->opts->require_eku = plgctx->opts->require_eku;
reqctx->opts->accept_secondary_eku = plgctx->opts->accept_secondary_eku;
@ -341,7 +350,7 @@ index ea9ba454df..54e7537600 100644
reqctx->opts->allow_upn = plgctx->opts->allow_upn;
reqctx->opts->require_crl_checking = plgctx->opts->require_crl_checking;
reqctx->opts->disable_freshness = plgctx->opts->disable_freshness;
@@ -1457,11 +1363,6 @@ handle_gic_opt(krb5_context context,
@@ -1457,11 +1362,6 @@ handle_gic_opt(krb5_context context,
retval = add_string_to_array(context, &plgctx->idopts->anchors, value);
if (retval)
return retval;
@ -354,10 +363,10 @@ index ea9ba454df..54e7537600 100644
if (strcmp(value, "yes") == 0)
plgctx->opts->disable_freshness = 1;
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 8bdbea8e95..04199b45a4 100644
index a291889b0d..f251e41064 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -181,45 +181,6 @@ krb5_error_code cms_signeddata_verify
@@ -183,48 +183,6 @@ krb5_error_code cms_signeddata_verify
int *is_signed); /* OUT
receives whether message is signed */
@ -370,6 +379,9 @@ index 8bdbea8e95..04199b45a4 100644
- pkinit_req_crypto_context req_cryptoctx, /* IN */
- pkinit_identity_crypto_context id_cryptoctx, /* IN */
- krb5_preauthtype pa_type, /* IN */
- int include_certchain, /* IN
- specifies whether the certificates field in
- SignedData should contain certificate path */
- unsigned char *key_pack, /* IN
- contains DER encoded ReplyKeyPack */
- unsigned int key_pack_len, /* IN
@ -404,10 +416,10 @@ index 8bdbea8e95..04199b45a4 100644
* This function retrieves the signer's identity, in a form that could
* be passed back in to a future invocation of this module as a candidate
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index af3fa9ee8b..980a89edc1 100644
index 32291e3ac0..76ad7526bb 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -66,26 +66,14 @@ static krb5_error_code create_signature
@@ -71,26 +71,14 @@ static krb5_error_code create_signature
(unsigned char **, unsigned int *, unsigned char *, unsigned int,
EVP_PKEY *pkey);
@ -434,7 +446,18 @@ index af3fa9ee8b..980a89edc1 100644
static ASN1_OBJECT * pkinit_pkcs7type2oid
(pkinit_plg_crypto_context plg_cryptoctx, int pkcs7_type);
@@ -115,20 +103,12 @@ static krb5_error_code pkinit_sign_data_pkcs11
@@ -111,31 +99,17 @@ static krb5_error_code pkinit_open_session
(krb5_context context, pkinit_identity_crypto_context id_cryptoctx);
static void * pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p);
static CK_RV pkinit_C_UnloadModule(void *handle);
-#ifdef SILLYDECRYPT
-CK_RV pkinit_C_Decrypt
-(pkinit_identity_crypto_context id_cryptoctx,
- CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen,
- CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen);
-#endif
static krb5_error_code pkinit_sign_data_pkcs11
(krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
unsigned char *data, unsigned int data_len,
unsigned char **sig, unsigned int *sig_len);
@ -455,18 +478,17 @@ index af3fa9ee8b..980a89edc1 100644
static krb5_error_code
create_krb5_invalidCertificates(krb5_context context,
@@ -140,10 +120,6 @@ create_krb5_invalidCertificates(krb5_context context,
@@ -147,9 +121,6 @@ create_krb5_invalidCertificates(krb5_context context,
static krb5_error_code
create_identifiers_from_stack(STACK_OF(X509) *sk,
krb5_external_principal_identifier *** ids);
-static int
-wrap_signeddata(unsigned char *data, unsigned int data_len,
- unsigned char **out, unsigned int *out_len);
-
static const char *
pkcs11err(int err);
@@ -2177,175 +2153,6 @@ cleanup:
static char *
pkinit_pkcs11_code_to_text(int err);
@@ -1791,176 +1762,6 @@ cleanup:
return retval;
}
@ -476,6 +498,7 @@ index af3fa9ee8b..980a89edc1 100644
- pkinit_req_crypto_context reqctx,
- pkinit_identity_crypto_context idctx,
- krb5_preauthtype pa_type,
- int include_certchain,
- unsigned char *key_pack,
- unsigned int key_pack_len,
- unsigned char **out,
@ -491,8 +514,8 @@ index af3fa9ee8b..980a89edc1 100644
- const EVP_CIPHER *cipher = NULL;
-
- retval = cms_signeddata_create(context, plgctx, reqctx, idctx,
- CMS_ENVEL_SERVER, key_pack, key_pack_len,
- &signed_data,
- CMS_ENVEL_SERVER, include_certchain,
- key_pack, key_pack_len, &signed_data,
- (unsigned int *)&signed_data_len);
- if (retval) {
- pkiDebug("failed to create pkcs7 signed data\n");
@ -642,7 +665,7 @@ index af3fa9ee8b..980a89edc1 100644
static krb5_error_code
crypto_retrieve_X509_sans(krb5_context context,
pkinit_plg_crypto_context plgctx,
@@ -3396,70 +3203,6 @@ pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
@@ -3539,70 +3340,6 @@ pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
}
@ -711,9 +734,9 @@ index af3fa9ee8b..980a89edc1 100644
-}
-
#ifndef WITHOUT_PKCS11
static struct plugin_file_handle *
load_pkcs11_module(krb5_context context, const char *modname,
@@ -3778,169 +3521,6 @@ pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
static void *
pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
@@ -3894,148 +3631,6 @@ pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
}
#endif
@ -726,10 +749,8 @@ index af3fa9ee8b..980a89edc1 100644
- X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
- id_cryptoctx->cert_index);
- EVP_PKEY *pkey = id_cryptoctx->my_key;
- EVP_PKEY_CTX *ctx = NULL;
- uint8_t *buf = NULL;
- size_t buf_len = 0;
- int ok;
- uint8_t *buf;
- int buf_len, decrypt_len;
-
- *decoded_data = NULL;
- *decoded_data_len = 0;
@ -739,40 +760,21 @@ index af3fa9ee8b..980a89edc1 100644
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
-
- ctx = EVP_PKEY_CTX_new(pkey, NULL);
- if (ctx == NULL)
- buf_len = EVP_PKEY_size(pkey);
- buf = malloc(buf_len + 10);
- if (buf == NULL)
- return KRB5KDC_ERR_PREAUTH_FAILED;
-
- ok = EVP_PKEY_decrypt_init(ctx);
- if (!ok)
- goto cleanup;
-
- /* Get the length of the eventual output. */
- ok = EVP_PKEY_decrypt(ctx, NULL, &buf_len, data, data_len);
- if (!ok) {
- pkiDebug("unable to decrypt received data\n");
- goto cleanup;
- }
-
- buf = malloc(buf_len);
- if (buf == NULL) {
- ok = 0;
- goto cleanup;
- }
-
- ok = EVP_PKEY_decrypt(ctx, buf, &buf_len, data, data_len);
- if (!ok) {
- pkiDebug("unable to decrypt received data\n");
- goto cleanup;
- decrypt_len = EVP_PKEY_decrypt_old(buf, data, data_len, pkey);
- if (decrypt_len <= 0) {
- pkiDebug("unable to decrypt received data (len=%d)\n", data_len);
- free(buf);
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
-
- *decoded_data = buf;
- *decoded_data_len = buf_len;
- buf = NULL;
-cleanup:
- zapfree(buf, buf_len);
- EVP_PKEY_CTX_free(ctx);
- return ok ? 0 : KRB5KDC_ERR_PREAUTH_FAILED;
- *decoded_data_len = decrypt_len;
- return 0;
-}
-
-#ifndef WITHOUT_PKCS11
@ -844,7 +846,7 @@ index af3fa9ee8b..980a89edc1 100644
- r = pkinit_C_Decrypt(id_cryptoctx, (CK_BYTE_PTR) data, (CK_ULONG) data_len,
- cp, &len);
- if (r != CKR_OK) {
- pkiDebug("C_Decrypt: %s\n", pkcs11err(r));
- pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r));
- if (r == CKR_BUFFER_TOO_SMALL)
- pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
- return KRB5KDC_ERR_PREAUTH_FAILED;
@ -883,7 +885,7 @@ index af3fa9ee8b..980a89edc1 100644
static krb5_error_code
pkinit_sign_data_fs(krb5_context context,
pkinit_identity_crypto_context id_cryptoctx,
@@ -5615,88 +5195,6 @@ cleanup:
@@ -5683,88 +5278,6 @@ cleanup:
return retval;
}
@ -973,7 +975,7 @@ index af3fa9ee8b..980a89edc1 100644
static void
print_dh(DH * dh, char *msg)
diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c
index 4c3d46bf5a..19db695a4d 100644
index bb2916bd5d..7af880bf5c 100644
--- a/src/plugins/preauth/pkinit/pkinit_lib.c
+++ b/src/plugins/preauth/pkinit/pkinit_lib.c
@@ -50,7 +50,6 @@ pkinit_init_req_opts(pkinit_req_opts **reqopts)
@ -993,10 +995,10 @@ index 4c3d46bf5a..19db695a4d 100644
opts->require_crl_checking = 0;
opts->require_freshness = 0;
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index 768a4e559f..aab21f951c 100644
index 3bff456f8f..4eab5a2761 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -821,132 +821,55 @@ pkinit_server_return_padata(krb5_context context,
@@ -826,133 +826,62 @@ pkinit_server_return_padata(krb5_context context,
retval = ENOMEM;
goto cleanup;
}
@ -1004,45 +1006,82 @@ index 768a4e559f..aab21f951c 100644
- rep->choice = choice_pa_pk_as_rep_encKeyPack;
- if (reqctx->rcv_auth_pack != NULL &&
- reqctx->rcv_auth_pack->clientPublicValue.length > 0) {
- reqctx->rcv_auth_pack->clientPublicValue != NULL) {
- subjectPublicKey = (unsigned char *)
- reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.data;
- subjectPublicKey_len =
- reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.length;
- rep->choice = choice_pa_pk_as_rep_dhInfo;
-
- pkiDebug("received DH key delivery AS REQ\n");
- retval = server_process_dh(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx,
- &dh_pubkey, &dh_pubkey_len,
- reqctx->cryptoctx, plgctx->idctx, subjectPublicKey,
- subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len,
- &server_key, &server_key_len);
- if (retval) {
- pkiDebug("failed to process/create dh parameters\n");
- goto cleanup;
- }
-
+ if (reqctx->rcv_auth_pack == NULL ||
+ reqctx->rcv_auth_pack->clientPublicValue == NULL) {
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ k5_setmsg(context, retval, _("Unsupported PKINIT RSA request"));
+ goto cleanup;
+ }
- /*
- * This is DH, so don't generate the key until after we
- * encode the reply, because the encoded reply is needed
- * to generate the key in some cases.
- */
-
+ subjectPublicKey = (unsigned char *)
+ reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.data;
+ subjectPublicKey_len =
+ reqctx->rcv_auth_pack->clientPublicValue->subjectPublicKey.length;
+ rep->choice = choice_pa_pk_as_rep_dhInfo;
+
+ pkiDebug("received DH key delivery AS REQ\n");
+ retval = server_process_dh(context, plgctx->cryptoctx, reqctx->cryptoctx,
+ plgctx->idctx, subjectPublicKey,
+ subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len,
+ &server_key, &server_key_len);
+ if (retval) {
+ pkiDebug("failed to process/create dh parameters\n");
+ goto cleanup;
+ }
- dhkey_info.subjectPublicKey.length = dh_pubkey_len;
- dhkey_info.subjectPublicKey.data = (char *)dh_pubkey;
- dhkey_info.nonce = request->nonce;
- dhkey_info.dhKeyExpiration = 0;
-
+ dhkey_info.subjectPublicKey.length = dh_pubkey_len;
+ dhkey_info.subjectPublicKey.data = (char *)dh_pubkey;
+ dhkey_info.nonce = request->nonce;
+ dhkey_info.dhKeyExpiration = 0;
- retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info,
- &encoded_dhkey_info);
- if (retval) {
- pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
- goto cleanup;
- }
-#ifdef DEBUG_ASN1
+ retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info,
+ &encoded_dhkey_info);
+ if (retval) {
+ pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
+ goto cleanup;
+ }
#ifdef DEBUG_ASN1
- print_buffer_bin((unsigned char *)encoded_dhkey_info->data,
- encoded_dhkey_info->length,
- "/tmp/kdc_dh_key_info");
-#endif
-
+ print_buffer_bin((unsigned char *)encoded_dhkey_info->data,
+ encoded_dhkey_info->length, "/tmp/kdc_dh_key_info");
#endif
- retval = cms_signeddata_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx,
- CMS_SIGN_SERVER,
- CMS_SIGN_SERVER, 1,
- (unsigned char *)
- encoded_dhkey_info->data,
- encoded_dhkey_info->length,
@ -1057,26 +1096,19 @@ index 768a4e559f..aab21f951c 100644
- } else {
- pkiDebug("received RSA key delivery AS REQ\n");
-
- retval = krb5_c_make_random_key(context, enctype, encrypting_key);
- if (retval) {
- pkiDebug("unable to make a session key\n");
- goto cleanup;
- }
-
- init_krb5_reply_key_pack(&key_pack);
- if (key_pack == NULL) {
- retval = ENOMEM;
- goto cleanup;
- }
+ if (reqctx->rcv_auth_pack == NULL ||
+ reqctx->rcv_auth_pack->clientPublicValue.length == 0) {
+ retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ k5_setmsg(context, retval, _("Unsupported PKINIT RSA request"));
+ goto cleanup;
+ }
- retval = krb5_c_make_random_key(context, enctype, &key_pack->replyKey);
- if (retval) {
- pkiDebug("unable to make a session key\n");
- goto cleanup;
- }
+ rep->choice = choice_pa_pk_as_rep_dhInfo;
- retval = krb5_c_make_checksum(context, 0, &key_pack->replyKey,
-
- retval = krb5_c_make_checksum(context, 0, encrypting_key,
- KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
- req_pkt, &key_pack->asChecksum);
- if (retval) {
@ -1089,32 +1121,24 @@ index 768a4e559f..aab21f951c 100644
- pkiDebug("checksum size = %d\n", key_pack->asChecksum.length);
- print_buffer(key_pack->asChecksum.contents,
- key_pack->asChecksum.length);
- pkiDebug("encrypting key (%d)\n", key_pack->replyKey.length);
- print_buffer(key_pack->replyKey.contents, key_pack->replyKey.length);
- pkiDebug("encrypting key (%d)\n", encrypting_key->length);
- print_buffer(encrypting_key->contents, encrypting_key->length);
-#endif
+ retval = server_process_dh(context, plgctx->cryptoctx, reqctx->cryptoctx,
+ plgctx->idctx, &dh_pubkey, &dh_pubkey_len,
+ &server_key, &server_key_len);
+ if (retval) {
+ pkiDebug("failed to process/create dh parameters\n");
+ goto cleanup;
+ }
-
- krb5_copy_keyblock_contents(context, encrypting_key,
- &key_pack->replyKey);
-
- retval = k5int_encode_krb5_reply_key_pack(key_pack,
- &encoded_key_pack);
- if (retval) {
- pkiDebug("failed to encode reply_key_pack\n");
- goto cleanup;
- }
+ dhkey_info.subjectPublicKey.length = dh_pubkey_len;
+ dhkey_info.subjectPublicKey.data = (char *)dh_pubkey;
+ dhkey_info.nonce = request->nonce;
+ dhkey_info.dhKeyExpiration = 0;
-
- rep->choice = choice_pa_pk_as_rep_encKeyPack;
- retval = cms_envelopeddata_create(context, plgctx->cryptoctx,
- reqctx->cryptoctx, plgctx->idctx,
- padata->pa_type,
- padata->pa_type, 1,
- (unsigned char *)
- encoded_key_pack->data,
- encoded_key_pack->length,
@ -1126,30 +1150,18 @@ index 768a4e559f..aab21f951c 100644
- error_message(retval));
- goto cleanup;
- }
+ retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info,
+ &encoded_dhkey_info);
+ if (retval) {
+ pkiDebug("encode_krb5_kdc_dh_key_info failed\n");
+ goto cleanup;
+ }
#ifdef DEBUG_ASN1
-#ifdef DEBUG_ASN1
- print_buffer_bin((unsigned char *)encoded_key_pack->data,
- encoded_key_pack->length,
- "/tmp/kdc_key_pack");
- print_buffer_bin(rep->u.encKeyPack.data, rep->u.encKeyPack.length,
- "/tmp/kdc_enc_key_pack");
+ print_buffer_bin((unsigned char *)encoded_dhkey_info->data,
+ encoded_dhkey_info->length, "/tmp/kdc_dh_key_info");
#endif
- retval = cb->replace_reply_key(context, rock, &key_pack->replyKey,
- FALSE);
- if (retval)
- goto cleanup;
-#endif
+ retval = cms_signeddata_create(context, plgctx->cryptoctx,
+ reqctx->cryptoctx, plgctx->idctx,
+ CMS_SIGN_SERVER,
+ (unsigned char *)encoded_dhkey_info->data,
+ CMS_SIGN_SERVER, 1,
+ (unsigned char *)
+ encoded_dhkey_info->data,
+ encoded_dhkey_info->length,
+ (unsigned char **)
+ &rep->u.dh_Info.dhSignedData.data,
@ -1162,13 +1174,12 @@ index 768a4e559f..aab21f951c 100644
- if (rep->choice == choice_pa_pk_as_rep_dhInfo &&
- ((reqctx->rcv_auth_pack != NULL &&
- reqctx->rcv_auth_pack->supportedKDFs != NULL))) {
-
+ if (reqctx->rcv_auth_pack != NULL &&
+ reqctx->rcv_auth_pack->supportedKDFs != NULL) {
/* If using the alg-agility KDF, put the algorithm in the reply
* before encoding it.
*/
@@ -973,41 +896,36 @@ pkinit_server_return_padata(krb5_context context,
@@ -980,35 +909,29 @@ pkinit_server_return_padata(krb5_context context,
"/tmp/kdc_as_rep");
#endif
@ -1189,7 +1200,7 @@ index 768a4e559f..aab21f951c 100644
- rep->u.dh_Info.kdfID,
- request->client, request->server,
- enctype, req_pkt, out_data,
- &reply_key);
- encrypting_key);
- if (retval) {
- pkiDebug("pkinit_alg_agility_kdf failed: %s\n",
- error_message(retval));
@ -1198,7 +1209,7 @@ index 768a4e559f..aab21f951c 100644
+ retval = pkinit_alg_agility_kdf(context, &secret, rep->u.dh_Info.kdfID,
+ request->client, request->server,
+ enctype, req_pkt, out_data,
+ &reply_key);
+ encrypting_key);
+ if (retval) {
+ pkiDebug("pkinit_alg_agility_kdf failed: %s\n",
+ error_message(retval));
@ -1208,34 +1219,25 @@ index 768a4e559f..aab21f951c 100644
- /* Otherwise, use the older octetstring2key() function */
- } else {
- retval = pkinit_octetstring2key(context, enctype, server_key,
+ /* Otherwise, use the older octetstring2key() function */
+ } else {
+ retval = pkinit_octetstring2key(context, enctype, server_key,
server_key_len, &reply_key);
- server_key_len, encrypting_key);
- if (retval) {
- pkiDebug("pkinit_octetstring2key failed: %s\n",
- error_message(retval));
- goto cleanup;
- }
- }
- retval = cb->replace_reply_key(context, rock, &reply_key, FALSE);
- if (retval)
+ /* Otherwise, use the older octetstring2key() function */
+ } else {
+ retval = pkinit_octetstring2key(context, enctype, server_key,
+ server_key_len, encrypting_key);
+ if (retval) {
+ pkiDebug("pkinit_octetstring2key failed: %s\n",
+ error_message(retval));
goto cleanup;
+ }
+ goto cleanup;
}
}
+ retval = cb->replace_reply_key(context, rock, &reply_key, FALSE);
+ if (retval)
+ goto cleanup;
+
*send_pa = malloc(sizeof(krb5_pa_data));
if (*send_pa == NULL) {
retval = ENOMEM;
diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
index 5ee39c085c..d385759145 100644
index bba3226bda..4f80e0b9b6 100644
--- a/src/plugins/preauth/pkinit/pkinit_trace.h
+++ b/src/plugins/preauth/pkinit/pkinit_trace.h
@@ -58,19 +58,10 @@
@ -1259,18 +1261,20 @@ index 5ee39c085c..d385759145 100644
TRACE(c, "PKINIT client config accepts KDC dNSName SAN {str}", host)
#define TRACE_PKINIT_CLIENT_SAN_MATCH_DNSNAME(c, host) \
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
index ec2356ea22..62e6c426d3 100755
index f224383c81..e8b7b4d207 100755
--- a/src/tests/t_pkinit.py
+++ b/src/tests/t_pkinit.py
@@ -179,13 +179,6 @@ id_conf = {'realms': {'$realm': {'pkinit_identities': [file_identity + 'X',
id_env = realm.special_env('idconf', False, krb5_conf=id_conf)
realm.kinit(realm.user_princ, expected_trace=msgs, env=id_env)
@@ -183,15 +183,6 @@ realm.kinit(realm.user_princ,
realm.klist(realm.user_princ)
realm.run([kvno, realm.host_princ])
-# Try again using RSA instead of DH.
-mark('FILE identity, no password, RSA')
-realm.pkinit(realm.user_princ, flags=['-X', 'flag_RSA_PROTOCOL=yes'],
- expected_trace=('PKINIT client making RSA request',
- 'PKINIT client verified RSA reply'))
-realm.kinit(realm.user_princ,
- flags=['-X', 'X509_user_identity=%s' % file_identity,
- '-X', 'flag_RSA_PROTOCOL=yes'],
- expected_trace=('PKINIT client making RSA request',
- 'PKINIT client verified RSA reply'))
-realm.klist(realm.user_princ)
-
# Test a DH parameter renegotiation by temporarily setting a 4096-bit

@ -0,0 +1,91 @@
From 6b4cdaac48e6b736b66ccc21f4eed7c6fc4c2e4a Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 4 Mar 2022 00:45:00 -0500
Subject: [PATCH] Try harder to avoid password change replay errors
Commit d7b3018d338fc9c989c3fa17505870f23c3759a8 (ticket 7905) changed
change_set_password() to prefer TCP. However, because UDP_LAST falls
back to UDP after one second, we can still get a replay error due to a
dropped packet, before the TCP layer has a chance to retry.
Instead, try k5_sendto() with NO_UDP, and only fall back to UDP after
TCP fails completely without reaching a server. In sendto_kdc.c,
implement an ONLY_UDP transport strategy to allow the UDP fallback.
ticket: 9037
---
src/lib/krb5/os/changepw.c | 9 ++++++++-
src/lib/krb5/os/os-proto.h | 1 +
src/lib/krb5/os/sendto_kdc.c | 12 ++++++++----
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c
index 9f968da7f..c59232586 100644
--- a/src/lib/krb5/os/changepw.c
+++ b/src/lib/krb5/os/changepw.c
@@ -255,9 +255,16 @@ change_set_password(krb5_context context,
callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
krb5_free_data_contents(callback_ctx.context, &chpw_rep);
+ /* UDP retransmits may be seen as replays. Only try UDP after other
+ * transports fail completely. */
code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm,
- &sl, UDP_LAST, &callback_info, &chpw_rep,
+ &sl, NO_UDP, &callback_info, &chpw_rep,
ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL);
+ if (code == KRB5_KDC_UNREACH) {
+ code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm,
+ &sl, ONLY_UDP, &callback_info, &chpw_rep,
+ ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL);
+ }
if (code)
goto cleanup;
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
index a16a34b74..ad3839131 100644
--- a/src/lib/krb5/os/os-proto.h
+++ b/src/lib/krb5/os/os-proto.h
@@ -49,6 +49,7 @@ typedef enum {
UDP_FIRST = 0,
UDP_LAST,
NO_UDP,
+ ONLY_UDP
} k5_transport_strategy;
/* A single server hostname or address. */
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index 82523c561..d76e24ccf 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -799,11 +799,14 @@ resolve_server(krb5_context context, const krb5_data *realm,
int err, result;
char portbuf[PORT_LENGTH];
- /* Skip UDP entries if we don't want UDP. */
+ /* Skip entries excluded by the strategy. */
if (strategy == NO_UDP && entry->transport == UDP)
return 0;
+ if (strategy == ONLY_UDP && entry->transport != UDP &&
+ entry->transport != TCP_OR_UDP)
+ return 0;
- transport = (strategy == UDP_FIRST) ? UDP : TCP;
+ transport = (strategy == UDP_FIRST || strategy == ONLY_UDP) ? UDP : TCP;
if (entry->hostname == NULL) {
/* Added by a module, so transport is either TCP or UDP. */
ai.ai_socktype = socktype_for_transport(entry->transport);
@@ -847,8 +850,9 @@ resolve_server(krb5_context context, const krb5_data *realm,
}
/* For TCP_OR_UDP entries, add each address again with the non-preferred
- * transport, unless we are avoiding UDP. Flag these as deferred. */
- if (retval == 0 && entry->transport == TCP_OR_UDP && strategy != NO_UDP) {
+ * transport, if there is one. Flag these as deferred. */
+ if (retval == 0 && entry->transport == TCP_OR_UDP &&
+ (strategy == UDP_FIRST || strategy == UDP_LAST)) {
transport = (strategy == UDP_FIRST) ? TCP : UDP;
for (a = addrs; a != 0 && retval == 0; a = a->ai_next) {
a->ai_socktype = socktype_for_transport(transport);
--
2.35.1

@ -0,0 +1,186 @@
From 6858ecbb9c407ff6d2b22cac283ea2461af1757b Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Thu, 20 Aug 2020 17:49:29 -0400
Subject: [PATCH] Unify kvno option documentation
Add missing kvno options to the kvno.rst synopsis and option
descriptions, and to the kvno usage message. Remove mention of '-h'
(help text), from kvno.rst as it is an implicit option. Note that the
three new caching options were added in release 1.19.
Indicate the two exclusions (-u/-S and --u2u with the S4U2Self options)
and dependency (-P on S4U2Self) where they are missing.
Switch xusage() to print only a single localized string, rather than
running each line of output through localization separately.
Leave kvno -C undocumented for now, as the semantics of
KRB5_GC_CANONICALIZE are minimally useful and likely to change.
[ghudson@mit.edu: edited documentation and commit message]
ticket: 7476
tags: pullup
target_version: 1.18-next
(cherry picked from commit becd1ad6830b526d08ddaf5b2b6f213154c6446c)
(cherry picked from commit 52e3695cc5ef00766e12adfe8ed276c2885e71bb)
---
doc/user/user_commands/kvno.rst | 24 +++++++++++++-----------
src/clients/kvno/kvno.c | 15 +++++++++------
src/man/kvno.man | 24 +++++++++++++-----------
3 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/doc/user/user_commands/kvno.rst b/doc/user/user_commands/kvno.rst
index 718313576..65c44e1c0 100644
--- a/doc/user/user_commands/kvno.rst
+++ b/doc/user/user_commands/kvno.rst
@@ -10,13 +10,9 @@ SYNOPSIS
[**-c** *ccache*]
[**-e** *etype*]
[**-q**]
-[**-h**]
+[**-u** | **-S** *sname*]
[**-P**]
-[**-S** *sname*]
-[**-I** *for_user*]
-[**-U** *for_user*]
-[**-F** *cert_file*]
-[**--u2u** *ccache*]
+[[{**-F** *cert_file* | {**-I** | **-U**} *for_user*} [**-P**]] | **--u2u** *ccache*]
*service1 service2* ...
@@ -39,13 +35,18 @@ OPTIONS
of all the services named on the command line. This is useful in
certain backward compatibility situations.
+**-k** *keytab*
+ Decrypt the acquired tickets using *keytab* to confirm their
+ validity.
+
**-q**
Suppress printing output when successful. If a service ticket
cannot be obtained, an error message will still be printed and
kvno will exit with nonzero status.
-**-h**
- Prints a usage statement and exits.
+**-u**
+ Use the unknown name type in requested service principal names.
+ This option Cannot be used with *-S*.
**-P**
Specifies that the *service1 service2* ... arguments are to be
@@ -76,16 +77,17 @@ OPTIONS
**--cached-only**
Only retrieve credentials already present in the cache, not from
- the KDC.
+ the KDC. (Added in release 1.19.)
**--no-store**
Do not store retrieved credentials in the cache. If
**--out-cache** is also specified, credentials will still be
- stored into the output credential cache.
+ stored into the output credential cache. (Added in release 1.19.)
**--out-cache** *ccache*
Initialize *ccache* and store all retrieved credentials into it.
- Do not store acquired credentials in the input cache.
+ Do not store acquired credentials in the input cache. (Added in
+ release 1.19.)
**--u2u** *ccache*
Requests a user-to-user ticket. *ccache* must contain a local
diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
index 9d85864f6..c5f6bf700 100644
--- a/src/clients/kvno/kvno.c
+++ b/src/clients/kvno/kvno.c
@@ -38,15 +38,18 @@
static char *prog;
static int quiet = 0;
+#define XUSAGE_BREAK "\n\t"
+
static void
xusage()
{
- fprintf(stderr, _("usage: %s [-C] [-u] [-c ccache] [-e etype]\n"), prog);
- fprintf(stderr, _("\t[-k keytab] [-S sname] [{-I | -U} for_user | "
- "[-F cert_file] [-P]]\n"));
- fprintf(stderr, _("\t[--cached-only] [--no-store] [--out-cache ccache] "
- "[--u2u ccache]\n"));
- fprintf(stderr, _("\tservice1 service2 ...\n"));
+ fprintf(stderr, _("usage: %s [-c ccache] [-e etype] [-k keytab] [-q] "
+ "[-u | -S sname]" XUSAGE_BREAK
+ "[[{-F cert_file | {-I | -U} for_user} [-P]] | "
+ "--u2u ccache]" XUSAGE_BREAK
+ "[--cached-only] [--no-store] [--out-cache] "
+ "service1 service2 ...\n"),
+ prog);
exit(1);
}
diff --git a/src/man/kvno.man b/src/man/kvno.man
index b9f6739eb..22318324d 100644
--- a/src/man/kvno.man
+++ b/src/man/kvno.man
@@ -36,13 +36,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
[\fB\-c\fP \fIccache\fP]
[\fB\-e\fP \fIetype\fP]
[\fB\-q\fP]
-[\fB\-h\fP]
+[\fB\-u\fP | \fB\-S\fP \fIsname\fP]
[\fB\-P\fP]
-[\fB\-S\fP \fIsname\fP]
-[\fB\-I\fP \fIfor_user\fP]
-[\fB\-U\fP \fIfor_user\fP]
-[\fB\-F\fP \fIcert_file\fP]
-[\fB\-\-u2u\fP \fIccache\fP]
+[[{\fB\-F\fP \fIcert_file\fP | {\fB\-I\fP | \fB\-U\fP} \fIfor_user\fP} [\fB\-P\fP]] | \fB\-\-u2u\fP \fIccache\fP]
\fIservice1 service2\fP ...
.SH DESCRIPTION
.sp
@@ -60,13 +56,18 @@ Specifies the enctype which will be requested for the session key
of all the services named on the command line. This is useful in
certain backward compatibility situations.
.TP
+\fB\-k\fP \fIkeytab\fP
+Decrypt the acquired tickets using \fIkeytab\fP to confirm their
+validity.
+.TP
\fB\-q\fP
Suppress printing output when successful. If a service ticket
cannot be obtained, an error message will still be printed and
kvno will exit with nonzero status.
.TP
-\fB\-h\fP
-Prints a usage statement and exits.
+\fB\-u\fP
+Use the unknown name type in requested service principal names.
+This option Cannot be used with \fI\-S\fP\&.
.TP
\fB\-P\fP
Specifies that the \fIservice1 service2\fP ... arguments are to be
@@ -97,16 +98,17 @@ certificate file must be in PEM format.
.TP
\fB\-\-cached\-only\fP
Only retrieve credentials already present in the cache, not from
-the KDC.
+the KDC. (Added in release 1.19.)
.TP
\fB\-\-no\-store\fP
Do not store retrieved credentials in the cache. If
\fB\-\-out\-cache\fP is also specified, credentials will still be
-stored into the output credential cache.
+stored into the output credential cache. (Added in release 1.19.)
.TP
\fB\-\-out\-cache\fP \fIccache\fP
Initialize \fIccache\fP and store all retrieved credentials into it.
-Do not store acquired credentials in the input cache.
+Do not store acquired credentials in the input cache. (Added in
+release 1.19.)
.TP
\fB\-\-u2u\fP \fIccache\fP
Requests a user\-to\-user ticket. \fIccache\fP must contain a local

@ -0,0 +1,184 @@
From b6ada496a285a7b350e28c97b53b6f659a9a94b9 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 788d094bff..001fb386a7 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 d2cf1eba2a..a7060aa733 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 84408fb68a..de5ed3a22b 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 95a6062e2a..38d371cb86 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 9b991ffe05..021e5f0723 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,237 @@
From 00a2ccfeaeac7a0019a73a97cfe33063ba90c7f3 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 26 Mar 2021 23:38:54 -0400
Subject: [PATCH] Use KCM_OP_RETRIEVE in KCM client
In kcm_retrieve(), try KCM_OP_RETRIEVE. Fall back to iteration if the
server doesn't implement it, or if we can an answer incompatible with
KRB5_TC_SUPPORTED_KTYPES.
In kcmserver.py, implement partial decoding for creds and cred tags so
that we can do a basic principal name match.
ticket: 8997 (new)
(cherry picked from commit 795ebba8c039be172ab93cd41105c73ffdba0fdb)
(cherry picked from commit c56d4b87de0f30a38dc61d374ad225d02d581eb3)
(cherry picked from commit ac0a117096324fa73afae291ed467f2ea66e279b)
---
src/include/kcm.h | 2 +-
src/lib/krb5/ccache/cc_kcm.c | 52 +++++++++++++++++++++++++++++++++---
src/tests/kcmserver.py | 44 +++++++++++++++++++++++++++---
src/tests/t_ccache.py | 11 +++++---
4 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/src/include/kcm.h b/src/include/kcm.h
index 9b66f1cbd..85c20d345 100644
--- a/src/include/kcm.h
+++ b/src/include/kcm.h
@@ -87,7 +87,7 @@ typedef enum kcm_opcode {
KCM_OP_INITIALIZE, /* (name, princ) -> () */
KCM_OP_DESTROY, /* (name) -> () */
KCM_OP_STORE, /* (name, cred) -> () */
- KCM_OP_RETRIEVE,
+ KCM_OP_RETRIEVE, /* (name, flags, credtag) -> (cred) */
KCM_OP_GET_PRINCIPAL, /* (name) -> (princ) */
KCM_OP_GET_CRED_UUID_LIST, /* (name) -> (uuid, ...) */
KCM_OP_GET_CRED_BY_UUID, /* (name, uuid) -> (cred) */
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
index dae622feb..b600c6f15 100644
--- a/src/lib/krb5/ccache/cc_kcm.c
+++ b/src/lib/krb5/ccache/cc_kcm.c
@@ -826,9 +826,55 @@ static krb5_error_code KRB5_CALLCONV
kcm_retrieve(krb5_context context, krb5_ccache cache, krb5_flags flags,
krb5_creds *mcred, krb5_creds *cred_out)
{
- /* There is a KCM opcode for retrieving creds, but Heimdal's client doesn't
- * use it. It causes the KCM daemon to actually make a TGS request. */
- return k5_cc_retrieve_cred_default(context, cache, flags, mcred, cred_out);
+ krb5_error_code ret;
+ struct kcmreq req = EMPTY_KCMREQ;
+ krb5_creds cred;
+ krb5_enctype *enctypes = NULL;
+
+ memset(&cred, 0, sizeof(cred));
+
+ /* Include KCM_GC_CACHED in flags to prevent Heimdal's sssd from making a
+ * TGS request itself. */
+ kcmreq_init(&req, KCM_OP_RETRIEVE, cache);
+ k5_buf_add_uint32_be(&req.reqbuf, map_tcflags(flags) | KCM_GC_CACHED);
+ k5_marshal_mcred(&req.reqbuf, mcred);
+ ret = cache_call(context, cache, &req);
+
+ /* Fall back to iteration if the server does not support retrieval. */
+ if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
+ ret = k5_cc_retrieve_cred_default(context, cache, flags, mcred,
+ cred_out);
+ goto cleanup;
+ }
+ if (ret)
+ goto cleanup;
+
+ ret = k5_unmarshal_cred(req.reply.ptr, req.reply.len, 4, &cred);
+ if (ret)
+ goto cleanup;
+
+ /* In rare cases we might retrieve a credential with a session key this
+ * context can't support, in which case we must retry using iteration. */
+ if (flags & KRB5_TC_SUPPORTED_KTYPES) {
+ ret = krb5_get_tgs_ktypes(context, cred.server, &enctypes);
+ if (ret)
+ goto cleanup;
+ if (!k5_etypes_contains(enctypes, cred.keyblock.enctype)) {
+ ret = k5_cc_retrieve_cred_default(context, cache, flags, mcred,
+ cred_out);
+ goto cleanup;
+ }
+ }
+
+ *cred_out = cred;
+ memset(&cred, 0, sizeof(cred));
+
+cleanup:
+ kcmreq_free(&req);
+ krb5_free_cred_contents(context, &cred);
+ free(enctypes);
+ /* Heimdal's KCM returns KRB5_CC_END if no cred is found. */
+ return (ret == KRB5_CC_END) ? KRB5_CC_NOTFOUND : map_invalid(ret);
}
static krb5_error_code KRB5_CALLCONV
diff --git a/src/tests/kcmserver.py b/src/tests/kcmserver.py
index 8c5e66ff1..25e6f2bbe 100644
--- a/src/tests/kcmserver.py
+++ b/src/tests/kcmserver.py
@@ -40,6 +40,7 @@ class KCMOpcodes(object):
INITIALIZE = 4
DESTROY = 5
STORE = 6
+ RETRIEVE = 7
GET_PRINCIPAL = 8
GET_CRED_UUID_LIST = 9
GET_CRED_BY_UUID = 10
@@ -54,6 +55,7 @@ class KCMOpcodes(object):
class KRB5Errors(object):
+ KRB5_CC_NOTFOUND = -1765328243
KRB5_CC_END = -1765328242
KRB5_CC_NOSUPP = -1765328137
KRB5_FCC_NOFILE = -1765328189
@@ -86,11 +88,29 @@ def get_cache(name):
return cache
+def unpack_data(argbytes):
+ dlen, = struct.unpack('>L', argbytes[:4])
+ return argbytes[4:dlen+4], argbytes[dlen+4:]
+
+
def unmarshal_name(argbytes):
offset = argbytes.find(b'\0')
return argbytes[0:offset], argbytes[offset+1:]
+def unmarshal_princ(argbytes):
+ # Ignore the type at argbytes[0:4].
+ ncomps, = struct.unpack('>L', argbytes[4:8])
+ realm, rest = unpack_data(argbytes[8:])
+ comps = []
+ for i in range(ncomps):
+ comp, rest = unpack_data(rest)
+ comps.append(comp)
+ # Asssume no quoting is needed.
+ princ = b'/'.join(comps) + b'@' + realm
+ return princ, rest
+
+
def op_gen_new(argbytes):
# Does not actually check for uniqueness.
global next_unique
@@ -126,6 +146,22 @@ def op_store(argbytes):
return 0, b''
+def op_retrieve(argbytes):
+ name, rest = unmarshal_name(argbytes)
+ # Ignore the flags at rest[0:4] and the header at rest[4:8].
+ # Assume there are client and server creds in the tag and match
+ # only against them.
+ cprinc, rest = unmarshal_princ(rest[8:])
+ sprinc, rest = unmarshal_princ(rest)
+ cache = get_cache(name)
+ for cred in (cache.creds[u] for u in cache.cred_uuids):
+ cred_cprinc, rest = unmarshal_princ(cred)
+ cred_sprinc, rest = unmarshal_princ(rest)
+ if cred_cprinc == cprinc and cred_sprinc == sprinc:
+ return 0, cred
+ return KRB5Errors.KRB5_CC_NOTFOUND, b''
+
+
def op_get_principal(argbytes):
name, rest = unmarshal_name(argbytes)
cache = get_cache(name)
@@ -199,6 +235,7 @@ ophandlers = {
KCMOpcodes.INITIALIZE : op_initialize,
KCMOpcodes.DESTROY : op_destroy,
KCMOpcodes.STORE : op_store,
+ KCMOpcodes.RETRIEVE : op_retrieve,
KCMOpcodes.GET_PRINCIPAL : op_get_principal,
KCMOpcodes.GET_CRED_UUID_LIST : op_get_cred_uuid_list,
KCMOpcodes.GET_CRED_BY_UUID : op_get_cred_by_uuid,
@@ -243,10 +280,11 @@ def service_request(s):
return True
parser = optparse.OptionParser()
-parser.add_option('-c', '--credlist', action='store_true', dest='credlist',
- default=False, help='Support KCM_OP_GET_CRED_LIST')
+parser.add_option('-f', '--fallback', action='store_true', dest='fallback',
+ default=False, help='Do not support RETRIEVE/GET_CRED_LIST')
(options, args) = parser.parse_args()
-if not options.credlist:
+if options.fallback:
+ del ophandlers[KCMOpcodes.RETRIEVE]
del ophandlers[KCMOpcodes.GET_CRED_LIST]
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
diff --git a/src/tests/t_ccache.py b/src/tests/t_ccache.py
index 90040fb7b..6ea9fb969 100755
--- a/src/tests/t_ccache.py
+++ b/src/tests/t_ccache.py
@@ -25,7 +25,7 @@ from k5test import *
kcm_socket_path = os.path.join(os.getcwd(), 'testdir', 'kcm')
conf = {'libdefaults': {'kcm_socket': kcm_socket_path,
'kcm_mach_service': '-'}}
-realm = K5Realm(create_host=False, krb5_conf=conf)
+realm = K5Realm(krb5_conf=conf)
keyctl = which('keyctl')
out = realm.run([klist, '-c', 'KEYRING:process:abcd'], expected_code=1)
@@ -71,6 +71,11 @@ def collection_test(realm, ccname):
realm.kinit('alice', password('alice'))
realm.run([klist], expected_msg='Default principal: alice@')
realm.run([klist, '-A', '-s'])
+ realm.run([kvno, realm.host_princ], expected_msg = 'kvno = 1')
+ realm.run([kvno, realm.host_princ], expected_msg = 'kvno = 1')
+ out = realm.run([klist])
+ if out.count(realm.host_princ) != 1:
+ fail('Wrong number of service tickets in cache')
realm.run([kdestroy])
output = realm.run([klist], expected_code=1)
if 'No credentials cache' not in output and 'not found' not in output:
@@ -126,14 +131,14 @@ def collection_test(realm, ccname):
collection_test(realm, 'DIR:' + os.path.join(realm.testdir, 'cc'))
-# Test KCM without and with GET_CRED_LIST support.
+# Test KCM with and without RETRIEVE and GET_CRED_LIST support.
kcmserver_path = os.path.join(srctop, 'tests', 'kcmserver.py')
kcmd = realm.start_server([sys.executable, kcmserver_path, kcm_socket_path],
'starting...')
collection_test(realm, 'KCM:')
stop_daemon(kcmd)
os.remove(kcm_socket_path)
-realm.start_server([sys.executable, kcmserver_path, '-c', kcm_socket_path],
+realm.start_server([sys.executable, kcmserver_path, '-f', kcm_socket_path],
'starting...')
collection_test(realm, 'KCM:')

@ -0,0 +1,124 @@
From baa2a485190d1b31f3dae06a18dc24d71dbe35bf Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Fri, 11 Mar 2022 12:04:14 +0100
Subject: [PATCH] Use SHA-256 instead of SHA-1 for PKINIT CMS digest
Various organizations including NIST have been strongly recommending to
stop using SHA-1 for digital signatures for some years already. CMS
digest is used to generate such signatures, hence it should be upgraded
to use SHA-256.
---
.../preauth/pkinit/pkinit_crypto_openssl.c | 40 ++++++++++---------
1 file changed, 22 insertions(+), 18 deletions(-)
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index dbb054378..32291e3ac 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -1234,7 +1234,7 @@ cms_signeddata_create(krb5_context context,
/* will not fill-out EVP_PKEY because it's on the smartcard */
/* Set digest algs */
- p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
+ p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha256);
if (p7si->digest_alg->parameter != NULL)
ASN1_TYPE_free(p7si->digest_alg->parameter);
@@ -1245,17 +1245,18 @@ cms_signeddata_create(krb5_context context,
/* Set sig algs */
if (p7si->digest_enc_alg->parameter != NULL)
ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
- p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
+ p7si->digest_enc_alg->algorithm =
+ OBJ_nid2obj(NID_sha256WithRSAEncryption);
if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
goto cleanup;
p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
/* add signed attributes */
- /* compute sha1 digest over the EncapsulatedContentInfo */
+ /* compute sha256 digest over the EncapsulatedContentInfo */
ctx = EVP_MD_CTX_new();
if (ctx == NULL)
goto cleanup;
- EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
EVP_DigestUpdate(ctx, data, data_len);
md_tmp = EVP_MD_CTX_md(ctx);
EVP_DigestFinal_ex(ctx, md_data, &md_len);
@@ -1283,12 +1284,14 @@ cms_signeddata_create(krb5_context context,
goto cleanup2;
#ifndef WITHOUT_PKCS11
- /* Some tokens can only do RSAEncryption without sha1 hash */
- /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
- * function and the hash value into an ASN.1 value of type DigestInfo
- * DigestInfo::=SEQUENCE {
- * digestAlgorithm AlgorithmIdentifier,
- * digest OCTET STRING }
+ /*
+ * Some tokens can only do RSAEncryption without a hash. To compute
+ * sha256WithRSAEncryption, encode the algorithm ID for the hash
+ * function and the hash value into an ASN.1 value of type DigestInfo:
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING
+ * }
*/
if (id_cryptoctx->pkcs11_method == 1 &&
id_cryptoctx->mech == CKM_RSA_PKCS) {
@@ -1304,7 +1307,7 @@ cms_signeddata_create(krb5_context context,
alg = X509_ALGOR_new();
if (alg == NULL)
goto cleanup2;
- X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha1), V_ASN1_NULL, NULL);
+ X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha256), V_ASN1_NULL, NULL);
alg_len = i2d_X509_ALGOR(alg, NULL);
digest = ASN1_OCTET_STRING_new();
@@ -1333,7 +1336,7 @@ cms_signeddata_create(krb5_context context,
#endif
{
pkiDebug("mech = %s\n",
- id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
+ id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA256_RSA_PKCS" : "FS");
retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
&sig, &sig_len);
}
@@ -4147,7 +4150,7 @@ create_signature(unsigned char **sig, unsigned int *sig_len,
ctx = EVP_MD_CTX_new();
if (ctx == NULL)
return ENOMEM;
- EVP_SignInit(ctx, EVP_sha1());
+ EVP_SignInit(ctx, EVP_sha256());
EVP_SignUpdate(ctx, data, data_len);
*sig_len = EVP_PKEY_size(pkey);
if ((*sig = malloc(*sig_len)) == NULL)
@@ -4623,10 +4626,11 @@ pkinit_get_certs_pkcs11(krb5_context context,
#ifndef PKINIT_USE_MECH_LIST
/*
- * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
- * many cards seems to be confused about whether they are capable of
- * this or not. The safe thing seems to be to ignore the mechanism list,
- * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
+ * We'd like to use CKM_SHA256_RSA_PKCS for signing if it's available, but
+ * historically many cards seem to be confused about whether they are
+ * capable of mechanisms or not. The safe thing seems to be to ignore the
+ * mechanism list, always use CKM_RSA_PKCS and calculate the sha256 digest
+ * ourselves.
*/
id_cryptoctx->mech = CKM_RSA_PKCS;
@@ -4654,7 +4658,7 @@ pkinit_get_certs_pkcs11(krb5_context context,
if (mechp[i] == CKM_RSA_PKCS) {
/* This seems backwards... */
id_cryptoctx->mech =
- (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
+ (info.flags & CKF_SIGN) ? CKM_SHA256_RSA_PKCS : CKM_RSA_PKCS;
}
}
free(mechp);
--
2.35.1

@ -1,4 +1,4 @@
From 0bf66d2018db92c95d3bab54a62f6a3265ceb158 Mon Sep 17 00:00:00 2001
From 2e871df888d526a15e9e91807480c15ca4e40618 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Thu, 26 Oct 2023 16:26:42 -0400
Subject: [PATCH] Wait indefinitely on KDC TCP connections
@ -15,10 +15,10 @@ ticket: 9105 (new)
2 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 65fb592d98..b7284c47df 100644
index 557094f6a2..98fe231813 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -357,7 +357,7 @@ The libdefaults section may contain any of the following relations:
@@ -358,7 +358,7 @@ The libdefaults section may contain any of the following relations:
for initial ticket requests. The default value is 0.
**request_timeout**
@ -28,7 +28,7 @@ index 65fb592d98..b7284c47df 100644
intervals between requests, so setting a low timeout may result in
fewer requests being attempted and/or some servers not being
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index 98247a1089..924f5b2d26 100644
index f57117126e..19b78aba24 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -134,7 +134,6 @@ struct conn_state {
@ -82,7 +82,7 @@ index 98247a1089..924f5b2d26 100644
#endif
return (*sret < 0) ? SOCKET_ERRNO : 0;
@@ -1099,11 +1107,6 @@ service_tcp_connect(krb5_context context, const krb5_data *realm,
@@ -1094,11 +1102,6 @@ service_tcp_connect(krb5_context context, const krb5_data *realm,
}
conn->state = WRITING;
@ -94,7 +94,7 @@ index 98247a1089..924f5b2d26 100644
return conn->service_write(context, realm, conn, selstate);
}
@@ -1378,19 +1381,18 @@ kill_conn:
@@ -1373,19 +1376,18 @@ kill_conn:
return FALSE;
}
@ -121,7 +121,7 @@ index 98247a1089..924f5b2d26 100644
}
static krb5_boolean
@@ -1413,9 +1415,9 @@ service_fds(krb5_context context, struct select_state *selstate,
@@ -1408,9 +1410,9 @@ service_fds(krb5_context context, struct select_state *selstate,
e = 0;
while (selstate->nfds > 0) {

@ -0,0 +1,73 @@
From 4e42a6786a06b7223f27536267492a463a700c76 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:45:26 -0400
Subject: [PATCH] [downstream] Adjust build configuration
Build binaries in this package as RELRO PIEs, libraries as partial RELRO,
and install shared libraries with the execute bit set on them. Prune out
the -L/usr/lib* and PIE flags where they might leak out and affect
apps which just want to link with the libraries. FIXME: needs to check and
not just assume that the compiler supports using these flags.
Last-updated: krb5-1.15-beta1
(cherry picked from commit 92508996ed4c69fa6f5cf855fdf10f34cfa07ec9)
---
src/build-tools/krb5-config.in | 7 +++++++
src/config/pre.in | 2 +-
src/config/shlib.conf | 5 +++--
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in
index c17cb5eb5..1891dea99 100755
--- a/src/build-tools/krb5-config.in
+++ b/src/build-tools/krb5-config.in
@@ -226,6 +226,13 @@ if test -n "$do_libs"; then
-e 's#\$(PTHREAD_CFLAGS)#'"$PTHREAD_CFLAGS"'#' \
-e 's#\$(CFLAGS)##'`
+ if test `dirname $libdir` = /usr ; then
+ lib_flags=`echo $lib_flags | sed -e "s#-L$libdir##" -e "s#$RPATH_FLAG$libdir##"`
+ fi
+ lib_flags=`echo $lib_flags | sed -e "s#-fPIE##g" -e "s#-pie##g"`
+ lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,relro##g"`
+ lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,now##g"`
+
if test $library = 'kdb'; then
lib_flags="$lib_flags -lkdb5 $KDB5_DB_LIB"
library=krb5
diff --git a/src/config/pre.in b/src/config/pre.in
index 917357df9..a8540ae2a 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -185,7 +185,7 @@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ $(INSTALL_STRIP)
INSTALL_SCRIPT=@INSTALL_PROGRAM@
INSTALL_DATA=@INSTALL_DATA@
INSTALL_SHLIB=@INSTALL_SHLIB@
-INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755 -o root
+INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755
## This is needed because autoconf will sometimes define @exec_prefix@ to be
## ${prefix}.
prefix=@prefix@
diff --git a/src/config/shlib.conf b/src/config/shlib.conf
index 3e4af6c02..2b20c3fda 100644
--- a/src/config/shlib.conf
+++ b/src/config/shlib.conf
@@ -423,7 +423,7 @@ mips-*-netbsd*)
# Linux ld doesn't default to stuffing the SONAME field...
# Use objdump -x to examine the fields of the library
# UNDEF_CHECK is suppressed by --enable-asan
- LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $(UNDEF_CHECK)'
+ LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $(UNDEF_CHECK) -Wl,-z,relro -Wl,--warn-shared-textrel'
UNDEF_CHECK='-Wl,--no-undefined'
# $(EXPORT_CHECK) runs export-check.pl when in maintainer mode.
LDCOMBINE_TAIL='-Wl,--version-script binutils.versions $(EXPORT_CHECK)'
@@ -435,7 +435,8 @@ mips-*-netbsd*)
SHLIB_EXPFLAGS='$(SHLIB_RPATH_FLAGS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
PROFFLAGS=-pg
PROG_RPATH_FLAGS='$(RPATH_FLAG)$(PROG_RPATH)'
- CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) $(LDFLAGS)'
+ CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) -pie -Wl,-z,relro -Wl,-z,now $(LDFLAGS)'
+ INSTALL_SHLIB='${INSTALL} -m755'
CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
CXX_LINK_SHARED='$(CXX) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CXXFLAGS) $(LDFLAGS)'
CXX_LINK_STATIC='$(CXX) $(PROG_LIBPATH) $(CXXFLAGS) $(LDFLAGS)'

@ -0,0 +1,126 @@
From 274464a6faaee694c30ae4d1412a8ab516b1a982 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 20 Sep 2023 16:22:06 +0200
Subject: [PATCH] [downstream] Allow to make AD-SIGNEDPATH optional
MIT krb5 1.20 and newer KDCs do generate a minimal PAC instead of
AD-SIGNEDPATH. As a consequence, an evidence ticket generated by an
older KDC would fail to be processed by a newer KDC for a constrained
delegation request.
This commit modifies this behavior to check the AD-SIGNEDPATH whenever
it is present in a TGS-REQ, but do not require it in case a PAC is
provided AND the KDB plugin supports its verification. This is done
regardless to the fact the constrained delegation request is from a
local realm or a cross-realm.
To enable this mechanism, the KDB plugin must set the
"optional_ab_signedpath" string attribute to "true" for the local TGS
principal.
---
src/include/kdb.h | 1 +
src/kdc/kdc_authdata.c | 65 +++++++++++++++++++++++++++++++++---------
2 files changed, 52 insertions(+), 14 deletions(-)
diff --git a/src/include/kdb.h b/src/include/kdb.h
index c56947ab81..95d07d0195 100644
--- a/src/include/kdb.h
+++ b/src/include/kdb.h
@@ -136,6 +136,7 @@
/* String attribute names recognized by krb5 */
#define KRB5_KDB_SK_SESSION_ENCTYPES "session_enctypes"
#define KRB5_KDB_SK_REQUIRE_AUTH "require_auth"
+#define KRB5_KDB_SK_OPTIONAL_AD_SIGNEDPATH "optional_ad_signedpath"
#if !defined(_WIN32)
diff --git a/src/kdc/kdc_authdata.c b/src/kdc/kdc_authdata.c
index 1ebe872467..c0fcccdf21 100644
--- a/src/kdc/kdc_authdata.c
+++ b/src/kdc/kdc_authdata.c
@@ -668,6 +668,13 @@ has_pac(krb5_context context, krb5_authdata **authdata)
return has_kdc_issued_authdata(context, authdata, KRB5_AUTHDATA_WIN2K_PAC);
}
+/* Return true if the AD-SIGNEDPATH is present in authorization data. */
+static krb5_boolean
+has_ad_signedpath(krb5_context context, krb5_authdata **authdata)
+{
+ return has_kdc_issued_authdata(context, authdata, KRB5_AUTHDATA_SIGNTICKET);
+}
+
/* Verify AD-SIGNTICKET authdata if we need to, and insert an AD-SIGNEDPATH
* element if we should. */
static krb5_error_code
@@ -680,24 +687,54 @@ handle_signticket(krb5_context context, unsigned int flags,
{
krb5_error_code ret = 0;
krb5_principal *deleg_path = NULL;
- krb5_boolean signed_path = FALSE;
- krb5_boolean s4u2proxy;
+ krb5_boolean s4u2proxy, adsp_present, adsp_optional, adsp_valid = FALSE;
+ char *str;
s4u2proxy = isflagset(flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);
- /* For cross-realm the Windows PAC must have been verified, and it
- * fulfills the same role as the signed path. */
- if (req->msg_type == KRB5_TGS_REQ &&
- (!isflagset(flags, KRB5_KDB_FLAG_CROSS_REALM) ||
- !has_pac(context, enc_tkt_req->authorization_data))) {
- ret = verify_signedpath(context, local_tgt, local_tgt_key, enc_tkt_req,
- &deleg_path, &signed_path);
- if (ret)
- goto cleanup;
+ if (req->msg_type == KRB5_TGS_REQ) {
+ adsp_present = has_ad_signedpath(context,
+ enc_tkt_req->authorization_data);
+
+ /* In case of constained delegation, based on the value of the
+ * "optional_ad_signedpath" string attribute of the local TGS principal:
+ * - "true": in case AD-SIGNEDPATH is absent, the PAC must be present
+ * - "false" or undefined: AD-SIGNEDPATH must be present
+ */
+ if (s4u2proxy && !adsp_present) {
+ ret = krb5_dbe_get_string(context, local_tgt,
+ KRB5_KDB_SK_OPTIONAL_AD_SIGNEDPATH,
+ &str);
+ /* TODO: should be using _krb5_conf_boolean(), but os-proto.h is not
+ * available here.
+ */
+ adsp_optional = !ret && str && (strncasecmp(str, "true", 4) == 0
+ || strncasecmp(str, "t", 1) == 0
+ || strncasecmp(str, "yes", 3) == 0
+ || strncasecmp(str, "y", 1) == 0
+ || strncasecmp(str, "1", 1) == 0
+ || strncasecmp(str, "on", 2) == 0);
+
+ if (!adsp_optional ||
+ !has_pac(context, enc_tkt_req->authorization_data)) {
+ ret = KRB5KDC_ERR_BADOPTION;
+ goto cleanup;
+ }
+ }
- if (s4u2proxy && signed_path == FALSE) {
- ret = KRB5KDC_ERR_BADOPTION;
- goto cleanup;
+ /* If AD-SIGNEDPATH is present, verify it */
+ if (adsp_present) {
+ ret = verify_signedpath(context, local_tgt, local_tgt_key,
+ enc_tkt_req, &deleg_path, &adsp_valid);
+ if (ret)
+ goto cleanup;
+
+ /* In case of contrained delegation, if AD-SIGNEDPATH is present, it
+ * has to be valid */
+ if (s4u2proxy && !adsp_valid) {
+ ret = KRB5KDC_ERR_BADOPTION;
+ goto cleanup;
+ }
}
}
--
2.41.0

@ -1,7 +1,7 @@
From 2dc9988da95cdd76335a00007b262272ca8c45b3 Mon Sep 17 00:00:00 2001
From f87e8a6734726bdd166f33757232a8c7cf9a9058 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Fri, 9 Nov 2018 15:12:21 -0500
Subject: [PATCH] [downstream] FIPS with PRNG and RADIUS and MD4
Subject: [PATCH] [downstream] FIPS with PRNG and RADIUS and MD4+5
NB: Use openssl's PRNG in FIPS mode and taint within krad.
@ -19,12 +19,11 @@ post6 restores MD4 (and therefore keygen-only RC4).
post7 restores MD5 and adds radius_md5_fips_override.
post8 silences a static analyzer warning.
Last-updated: krb5-1.20
Last-updated: krb5-1.17
(cherry picked from commit bf8521bfaa4a4d54f6eb94f785c68942f4afa055)
---
doc/admin/conf_files/krb5_conf.rst | 6 +++
src/lib/crypto/krb/prng.c | 15 +++++-
src/lib/crypto/krb/prng.c | 11 ++++-
.../crypto/openssl/enc_provider/camellia.c | 6 +++
src/lib/crypto/openssl/enc_provider/rc4.c | 13 +++++-
.../crypto/openssl/hash_provider/hash_evp.c | 12 +++++
@ -38,13 +37,13 @@ Last-updated: krb5-1.20
src/lib/krad/t_attrset.c | 4 +-
src/plugins/preauth/spake/spake_client.c | 6 +++
src/plugins/preauth/spake/spake_kdc.c | 6 +++
15 files changed, 155 insertions(+), 33 deletions(-)
15 files changed, 151 insertions(+), 33 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index f22d5db11b..a33711d918 100644
index 1d2aa7f68..3a8b9cf47 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -330,6 +330,12 @@ The libdefaults section may contain any of the following relations:
@@ -331,6 +331,12 @@ The libdefaults section may contain any of the following relations:
qualification of shortnames, set this relation to the empty string
with ``qualify_shortname = ""``. (New in release 1.18.)
@ -58,26 +57,22 @@ index f22d5db11b..a33711d918 100644
If this flag is true, reverse name lookup will be used in addition
to forward name lookup to canonicalizing hostnames for use in
diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c
index d6b79e2dea..9e80a03d21 100644
index cb9ca9b98..f0e9984ca 100644
--- a/src/lib/crypto/krb/prng.c
+++ b/src/lib/crypto/krb/prng.c
@@ -26,6 +26,12 @@
@@ -26,6 +26,8 @@
#include "crypto_int.h"
+#include <openssl/rand.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+#include <openssl/crypto.h>
+#endif
+
krb5_error_code KRB5_CALLCONV
krb5_c_random_seed(krb5_context context, krb5_data *data)
{
@@ -96,9 +102,16 @@ cleanup:
static krb5_boolean
get_os_entropy(unsigned char *buf, size_t len)
@@ -99,9 +101,16 @@ krb5_boolean
k5_get_os_entropy(unsigned char *buf, size_t len, int strong)
{
const char *device;
-#if defined(__linux__) && defined(SYS_getrandom)
int r;
@ -93,10 +88,10 @@ index d6b79e2dea..9e80a03d21 100644
/*
* Pull from the /dev/urandom pool, but require it to have been seeded.
diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
index 01920e6ce1..d9f327add6 100644
index 2da691329..f79679a0b 100644
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
@@ -387,6 +387,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
@@ -304,6 +304,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE];
struct iov_cursor cursor;
@ -106,7 +101,7 @@ index 01920e6ce1..d9f327add6 100644
if (output->length < CAMELLIA_BLOCK_SIZE)
return KRB5_BAD_MSIZE;
@@ -418,6 +421,9 @@ static krb5_error_code
@@ -331,6 +334,9 @@ static krb5_error_code
krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
krb5_data *state)
{
@ -117,10 +112,10 @@ index 01920e6ce1..d9f327add6 100644
state->data = (void *) malloc(16);
if (state->data == NULL)
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
index 448d563348..ce63cb5f1b 100644
index a65d57b7a..6ccaca94a 100644
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
@@ -69,6 +69,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
@@ -66,6 +66,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
EVP_CIPHER_CTX *ctx = NULL;
struct arcfour_state *arcstate;
@ -130,7 +125,7 @@ index 448d563348..ce63cb5f1b 100644
arcstate = (state != NULL) ? (void *)state->data : NULL;
if (arcstate != NULL) {
ctx = arcstate->ctx;
@@ -116,7 +119,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
@@ -113,7 +116,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
static void
k5_arcfour_free_state(krb5_data *state)
{
@ -144,7 +139,7 @@ index 448d563348..ce63cb5f1b 100644
EVP_CIPHER_CTX_free(arcstate->ctx);
free(arcstate);
@@ -128,6 +136,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
@@ -125,6 +133,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
{
struct arcfour_state *arcstate;
@ -155,10 +150,10 @@ index 448d563348..ce63cb5f1b 100644
* The cipher state here is a saved pointer to a struct arcfour_state
* object, rather than a flat byte array as in most enc providers. The
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
index f2fbffdb29..11659908bb 100644
index 1e0fb8fc3..2eb5139c0 100644
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
@@ -60,6 +60,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
@@ -49,6 +49,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
if (ctx == NULL)
return ENOMEM;
@ -170,7 +165,7 @@ index f2fbffdb29..11659908bb 100644
ok = EVP_DigestInit_ex(ctx, type, NULL);
for (i = 0; i < num_data; i++) {
if (!SIGN_IOV(&data[i]))
@@ -78,6 +83,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
@@ -64,12 +69,19 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
static krb5_error_code
hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
{
@ -182,7 +177,6 @@ index f2fbffdb29..11659908bb 100644
return hash_evp(EVP_md4(), data, num_data, output);
}
@@ -90,6 +100,8 @@ const struct krb5_hash_provider krb5int_hash_md4 = {
static krb5_error_code
hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
{
@ -192,24 +186,24 @@ index f2fbffdb29..11659908bb 100644
}
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
index bf12b8d6a0..f21e268f7f 100644
index 7dc59dcc0..769a50c00 100644
--- a/src/lib/crypto/openssl/hmac.c
+++ b/src/lib/crypto/openssl/hmac.c
@@ -111,7 +111,11 @@ map_digest(const struct krb5_hash_provider *hash)
@@ -103,7 +103,11 @@ map_digest(const struct krb5_hash_provider *hash)
return EVP_sha256();
else if (hash == &krb5int_hash_sha384)
else if (!strncmp(hash->hash_name, "SHA-384",7))
return EVP_sha384();
- else if (hash == &krb5int_hash_md5)
- else if (!strncmp(hash->hash_name, "MD5", 3))
+
+ if (FIPS_mode())
+ return NULL;
+
+ if (hash == &krb5int_hash_md5)
+ if (!strncmp(hash->hash_name, "MD5", 3))
return EVP_md5();
else if (hash == &krb5int_hash_md4)
else if (!strncmp(hash->hash_name, "MD4", 3))
return EVP_md4();
diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
index 9c13d9d755..42d354a3b5 100644
index 9c13d9d75..42d354a3b 100644
--- a/src/lib/krad/attr.c
+++ b/src/lib/krad/attr.c
@@ -38,7 +38,8 @@
@ -333,7 +327,7 @@ index 9c13d9d755..42d354a3b5 100644
krad_attr
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
index f309f1581c..6ec031e320 100644
index 03c613716..d89982a13 100644
--- a/src/lib/krad/attrset.c
+++ b/src/lib/krad/attrset.c
@@ -167,7 +167,8 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
@ -356,7 +350,7 @@ index f309f1581c..6ec031e320 100644
return retval;
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
index 7619563fc5..e123763954 100644
index 996a89372..312dc8258 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -39,6 +39,8 @@
@ -402,7 +396,7 @@ index 7619563fc5..e123763954 100644
/* Decode attributes from a buffer. */
krb5_error_code
@@ -156,4 +167,17 @@ gai_error_code(int err)
@@ -152,4 +163,17 @@ gai_error_code(int err)
}
}
@ -414,14 +408,14 @@ index 7619563fc5..e123763954 100644
+ if (!FIPS_mode())
+ return 0;
+
+ (void)profile_get_boolean(ctx->profile, "libdefaults",
+ "radius_md5_fips_override", NULL, 0, &val);
+ profile_get_boolean(ctx->profile, "libdefaults",
+ "radius_md5_fips_override", NULL, 0, &val);
+ return !val;
+}
+
#endif /* INTERNAL_H_ */
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
index c597174b65..fc2d248001 100644
index c597174b6..fc2d24800 100644
--- a/src/lib/krad/packet.c
+++ b/src/lib/krad/packet.c
@@ -53,12 +53,6 @@ typedef unsigned char uchar;
@ -482,7 +476,7 @@ index c597174b65..fc2d248001 100644
}
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
index 06ae751bc8..929f1cef67 100644
index 437f7e91a..0f90443ce 100644
--- a/src/lib/krad/remote.c
+++ b/src/lib/krad/remote.c
@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr)
@ -503,7 +497,7 @@ index 06ae751bc8..929f1cef67 100644
request_finish(r, 0, rsp);
break;
}
@@ -460,6 +460,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
@@ -455,6 +455,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
(krad_packet_iter_cb)iterator, &r, &tmp);
if (retval != 0)
goto error;
@ -517,7 +511,7 @@ index 06ae751bc8..929f1cef67 100644
K5_TAILQ_FOREACH(r, &rr->list, list) {
if (r->request == tmp) {
diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c
index eb2a780c89..4d285ad9de 100644
index eb2a780c8..4d285ad9d 100644
--- a/src/lib/krad/t_attr.c
+++ b/src/lib/krad/t_attr.c
@@ -50,6 +50,7 @@ main()
@ -538,7 +532,7 @@ index eb2a780c89..4d285ad9de 100644
insist(len == sizeof(encoded));
insist(memcmp(outbuf, encoded, len) == 0);
diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
index 7928335ca4..0f95762534 100644
index 7928335ca..0f9576253 100644
--- a/src/lib/krad/t_attrset.c
+++ b/src/lib/krad/t_attrset.c
@@ -49,6 +49,7 @@ main()
@ -560,7 +554,7 @@ index 7928335ca4..0f95762534 100644
/* Manually encode User-Name. */
diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
index 00734a13b5..a3ce22b70f 100644
index 00734a13b..a3ce22b70 100644
--- a/src/plugins/preauth/spake/spake_client.c
+++ b/src/plugins/preauth/spake/spake_client.c
@@ -38,6 +38,8 @@
@ -584,7 +578,7 @@ index 00734a13b5..a3ce22b70f 100644
vt->name = "spake";
vt->pa_type_list = pa_types;
diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
index 1a772d450f..232e78bc05 100644
index 88c964ce1..c7df0392f 100644
--- a/src/plugins/preauth/spake/spake_kdc.c
+++ b/src/plugins/preauth/spake/spake_kdc.c
@@ -41,6 +41,8 @@
@ -596,7 +590,7 @@ index 1a772d450f..232e78bc05 100644
/*
* The SPAKE kdcpreauth module uses a secure cookie containing the following
* concatenated fields (all integer fields are big-endian):
@@ -551,6 +553,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
@@ -571,6 +573,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
if (maj_ver != 1)
return KRB5_PLUGIN_VER_NOTSUPP;
@ -607,6 +601,3 @@ index 1a772d450f..232e78bc05 100644
vt = (krb5_kdcpreauth_vtable)vtable;
vt->name = "spake";
vt->pa_type_list = pa_types;
--
2.41.0

@ -0,0 +1,156 @@
From 10b32480395a01798b21818e884a593930b400d1 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 27 Apr 2022 15:29:08 +0200
Subject: [PATCH] Fix dejagnu unit tests directory name for RPC lib
This commit renames RPC library's unit tests directory to match the
newly enforced naming convention of dejagnu.
Resolves: rhbz#2070879
Signed-off-by: Julien Rische <jrische@redhat.com>
---
src/configure.ac | 2 +-
src/lib/rpc/Makefile.in | 2 +-
src/lib/rpc/{unit-test => testsuite}/Makefile.in | 10 +++++-----
src/lib/rpc/{unit-test => testsuite}/client.c | 0
src/lib/rpc/{unit-test => testsuite}/config/unix.exp | 0
src/lib/rpc/{unit-test => testsuite}/deps | 0
src/lib/rpc/{unit-test => testsuite}/lib/helpers.exp | 0
.../rpc/{unit-test => testsuite}/rpc_test.0/expire.exp | 0
.../{unit-test => testsuite}/rpc_test.0/fullrun.exp | 0
.../rpc/{unit-test => testsuite}/rpc_test.0/gsserr.exp | 0
src/lib/rpc/{unit-test => testsuite}/rpc_test.h | 0
src/lib/rpc/{unit-test => testsuite}/rpc_test.x | 0
src/lib/rpc/{unit-test => testsuite}/rpc_test_clnt.c | 0
src/lib/rpc/{unit-test => testsuite}/rpc_test_svc.c | 0
src/lib/rpc/{unit-test => testsuite}/server.c | 0
15 files changed, 7 insertions(+), 7 deletions(-)
rename src/lib/rpc/{unit-test => testsuite}/Makefile.in (93%)
rename src/lib/rpc/{unit-test => testsuite}/client.c (100%)
rename src/lib/rpc/{unit-test => testsuite}/config/unix.exp (100%)
rename src/lib/rpc/{unit-test => testsuite}/deps (100%)
rename src/lib/rpc/{unit-test => testsuite}/lib/helpers.exp (100%)
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.0/expire.exp (100%)
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.0/fullrun.exp (100%)
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.0/gsserr.exp (100%)
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.h (100%)
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.x (100%)
rename src/lib/rpc/{unit-test => testsuite}/rpc_test_clnt.c (100%)
rename src/lib/rpc/{unit-test => testsuite}/rpc_test_svc.c (100%)
rename src/lib/rpc/{unit-test => testsuite}/server.c (100%)
diff --git a/src/configure.ac b/src/configure.ac
index 37e36b76d..2a48aa83d 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1497,7 +1497,7 @@ V5_AC_OUTPUT_MAKEFILE(.
lib/gssapi lib/gssapi/generic lib/gssapi/krb5 lib/gssapi/spnego
lib/gssapi/mechglue
- lib/rpc lib/rpc/unit-test
+ lib/rpc lib/rpc/testsuite
lib/kadm5 lib/kadm5/clnt lib/kadm5/srv lib/kadm5/testsuite
lib/krad
diff --git a/src/lib/rpc/Makefile.in b/src/lib/rpc/Makefile.in
index 6b5f1e70a..78c7a1326 100644
--- a/src/lib/rpc/Makefile.in
+++ b/src/lib/rpc/Makefile.in
@@ -2,7 +2,7 @@ mydir=lib$(S)rpc
BUILDTOP=$(REL)..$(S)..
DEFINES = -DGSSAPI_KRB5 -DDEBUG_GSSAPI=0 -DGSSRPC__IMPL
-SUBDIRS=unit-test
+SUBDIRS=testsuite
##DOSBUILDTOP = ..\..
##DOSLIBNAME=libgssrpc.lib
diff --git a/src/lib/rpc/unit-test/Makefile.in b/src/lib/rpc/testsuite/Makefile.in
similarity index 93%
rename from src/lib/rpc/unit-test/Makefile.in
rename to src/lib/rpc/testsuite/Makefile.in
index 0b6e5203d..0fab26c10 100644
--- a/src/lib/rpc/unit-test/Makefile.in
+++ b/src/lib/rpc/testsuite/Makefile.in
@@ -1,4 +1,4 @@
-mydir=lib$(S)rpc$(S)unit-test
+mydir=lib$(S)rpc$(S)testsuite
BUILDTOP=$(REL)..$(S)..$(S)..
OBJS= client.o rpc_test_clnt.o rpc_test_svc.o server.o
@@ -34,19 +34,19 @@ runenv.exp: Makefile
# rm -f rpc_test.h rpc_test_clnt.c rpc_test_svc.c
#
-check unit-test: unit-test-@DO_TEST@
+check testsuite: testsuite-@DO_TEST@
-unit-test-:
+testsuite-:
@echo "+++"
@echo "+++ WARNING: lib/rpc unit tests not run."
@echo "+++ Either tcl, runtest, or Perl is unavailable."
@echo "+++"
@echo 'Skipped rpc tests: runtest or Perl not found' >> $(SKIPTESTS)
-unit-test-ok: unit-test-body
+testsuite-ok: testsuite-body
PASS=@PASS@
-unit-test-body: runenv.sh runenv.exp
+testsuite-body: runenv.sh runenv.exp
$(RM) krb5cc_rpc_test_*
$(ENV_SETUP) $(VALGRIND) $(START_SERVERS)
RPC_TEST_KEYTAB=/tmp/rpc_test_keytab.$$$$ ; export RPC_TEST_KEYTAB ; \
diff --git a/src/lib/rpc/unit-test/client.c b/src/lib/rpc/testsuite/client.c
similarity index 100%
rename from src/lib/rpc/unit-test/client.c
rename to src/lib/rpc/testsuite/client.c
diff --git a/src/lib/rpc/unit-test/config/unix.exp b/src/lib/rpc/testsuite/config/unix.exp
similarity index 100%
rename from src/lib/rpc/unit-test/config/unix.exp
rename to src/lib/rpc/testsuite/config/unix.exp
diff --git a/src/lib/rpc/unit-test/deps b/src/lib/rpc/testsuite/deps
similarity index 100%
rename from src/lib/rpc/unit-test/deps
rename to src/lib/rpc/testsuite/deps
diff --git a/src/lib/rpc/unit-test/lib/helpers.exp b/src/lib/rpc/testsuite/lib/helpers.exp
similarity index 100%
rename from src/lib/rpc/unit-test/lib/helpers.exp
rename to src/lib/rpc/testsuite/lib/helpers.exp
diff --git a/src/lib/rpc/unit-test/rpc_test.0/expire.exp b/src/lib/rpc/testsuite/rpc_test.0/expire.exp
similarity index 100%
rename from src/lib/rpc/unit-test/rpc_test.0/expire.exp
rename to src/lib/rpc/testsuite/rpc_test.0/expire.exp
diff --git a/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp b/src/lib/rpc/testsuite/rpc_test.0/fullrun.exp
similarity index 100%
rename from src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
rename to src/lib/rpc/testsuite/rpc_test.0/fullrun.exp
diff --git a/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp b/src/lib/rpc/testsuite/rpc_test.0/gsserr.exp
similarity index 100%
rename from src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
rename to src/lib/rpc/testsuite/rpc_test.0/gsserr.exp
diff --git a/src/lib/rpc/unit-test/rpc_test.h b/src/lib/rpc/testsuite/rpc_test.h
similarity index 100%
rename from src/lib/rpc/unit-test/rpc_test.h
rename to src/lib/rpc/testsuite/rpc_test.h
diff --git a/src/lib/rpc/unit-test/rpc_test.x b/src/lib/rpc/testsuite/rpc_test.x
similarity index 100%
rename from src/lib/rpc/unit-test/rpc_test.x
rename to src/lib/rpc/testsuite/rpc_test.x
diff --git a/src/lib/rpc/unit-test/rpc_test_clnt.c b/src/lib/rpc/testsuite/rpc_test_clnt.c
similarity index 100%
rename from src/lib/rpc/unit-test/rpc_test_clnt.c
rename to src/lib/rpc/testsuite/rpc_test_clnt.c
diff --git a/src/lib/rpc/unit-test/rpc_test_svc.c b/src/lib/rpc/testsuite/rpc_test_svc.c
similarity index 100%
rename from src/lib/rpc/unit-test/rpc_test_svc.c
rename to src/lib/rpc/testsuite/rpc_test_svc.c
diff --git a/src/lib/rpc/unit-test/server.c b/src/lib/rpc/testsuite/server.c
similarity index 100%
rename from src/lib/rpc/unit-test/server.c
rename to src/lib/rpc/testsuite/server.c
--
2.35.1

@ -1,4 +1,4 @@
From 021f1f1bf690694945a3ab0a5221797a7bcd6a99 Mon Sep 17 00:00:00 2001
From 791fe183bf67dcab6d044b23d8daaf4a3a96be48 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:30:53 -0400
Subject: [PATCH] [downstream] SELinux integration
@ -36,9 +36,8 @@ The selabel APIs for looking up the context should be thread-safe (per
Red Hat #273081), so switching to using them instead of matchpathcon(),
which we used earlier, is some improvement.
Last-updated: krb5-1.20.1
[jrische@redhat.com: Replace deprecated security_context_t by char *:
- src/util/support/selinux.c]
Last-updated: krb5-1.18-beta1
(cherry picked from commit 0f8851a23a7b6fa0e195e01d0475e9e55707adf2)
---
src/aclocal.m4 | 48 +++
src/build-tools/krb5-config.in | 3 +-
@ -63,16 +62,16 @@ Last-updated: krb5-1.20.1
.../kdb/ldap/ldap_util/kdb5_ldap_services.c | 11 +-
src/util/profile/prof_file.c | 3 +-
src/util/support/Makefile.in | 3 +-
src/util/support/selinux.c | 405 ++++++++++++++++++
24 files changed, 572 insertions(+), 21 deletions(-)
src/util/support/selinux.c | 406 ++++++++++++++++++
24 files changed, 573 insertions(+), 21 deletions(-)
create mode 100644 src/include/k5-label.h
create mode 100644 src/util/support/selinux.c
diff --git a/src/aclocal.m4 b/src/aclocal.m4
index ce3c5a9bac..3331970930 100644
index 830203683..6796fec53 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -85,6 +85,7 @@ AC_SUBST_FILE(libnodeps_frag)
@@ -89,6 +89,7 @@ AC_SUBST_FILE(libnodeps_frag)
dnl
KRB5_AC_PRAGMA_WEAK_REF
WITH_LDAP
@ -80,7 +79,7 @@ index ce3c5a9bac..3331970930 100644
KRB5_LIB_PARAMS
KRB5_AC_INITFINI
KRB5_AC_ENABLE_THREADS
@@ -1526,4 +1527,51 @@ AC_SUBST(PAM_LIBS)
@@ -1743,4 +1744,51 @@ AC_SUBST(PAM_LIBS)
AC_SUBST(PAM_MAN)
AC_SUBST(NON_PAM_MAN)
])dnl
@ -133,10 +132,10 @@ index ce3c5a9bac..3331970930 100644
+AC_SUBST(SELINUX_LIBS)
+])dnl
diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in
index 8e6eb86601..7677f37359 100755
index f6184da3f..c17cb5eb5 100755
--- a/src/build-tools/krb5-config.in
+++ b/src/build-tools/krb5-config.in
@@ -40,6 +40,7 @@ DL_LIB='@DL_LIB@'
@@ -41,6 +41,7 @@ DL_LIB='@DL_LIB@'
DEFCCNAME='@DEFCCNAME@'
DEFKTNAME='@DEFKTNAME@'
DEFCKTNAME='@DEFCKTNAME@'
@ -144,7 +143,7 @@ index 8e6eb86601..7677f37359 100755
LIBS='@LIBS@'
GEN_LIB=@GEN_LIB@
@@ -253,7 +254,7 @@ if test -n "$do_libs"; then
@@ -255,7 +256,7 @@ if test -n "$do_libs"; then
fi
# If we ever support a flag to generate output suitable for static
@ -154,7 +153,7 @@ index 8e6eb86601..7677f37359 100755
echo $lib_flags
diff --git a/src/config/pre.in b/src/config/pre.in
index a0c60c70b3..7eaa2f351c 100644
index ce87e21ca..917357df9 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -177,6 +177,7 @@ LD = $(PURE) @LD@
@ -165,7 +164,7 @@ index a0c60c70b3..7eaa2f351c 100644
INSTALL=@INSTALL@
INSTALL_STRIP=
@@ -379,7 +380,7 @@ SUPPORT_LIB = -l$(SUPPORT_LIBNAME)
@@ -402,7 +403,7 @@ SUPPORT_LIB = -l$(SUPPORT_LIBNAME)
# HESIOD_LIBS is -lhesiod...
HESIOD_LIBS = @HESIOD_LIBS@
@ -175,10 +174,10 @@ index a0c60c70b3..7eaa2f351c 100644
GSS_LIBS = $(GSS_KRB5_LIB)
# needs fixing if ever used on macOS!
diff --git a/src/configure.ac b/src/configure.ac
index 587221936e..69be9030f8 100644
index d1f576124..440a22bd9 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1401,6 +1401,8 @@ AC_PATH_PROG(GROFF, groff)
@@ -1392,6 +1392,8 @@ AC_PATH_PROG(GROFF, groff)
KRB5_WITH_PAM
@ -188,7 +187,7 @@ index 587221936e..69be9030f8 100644
if test "${localedir+set}" != set; then
localedir='$(datadir)/locale'
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 1d1c8293f4..768110e5ef 100644
index 9616b24bf..0d9af3d95 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -128,6 +128,7 @@ typedef unsigned char u_char;
@ -201,7 +200,7 @@ index 1d1c8293f4..768110e5ef 100644
#define KRB5_KDB_MAX_RLIFE (60*60*24*7) /* one week */
diff --git a/src/include/k5-label.h b/src/include/k5-label.h
new file mode 100644
index 0000000000..dfaaa847cb
index 000000000..dfaaa847c
--- /dev/null
+++ b/src/include/k5-label.h
@@ -0,0 +1,32 @@
@ -238,7 +237,7 @@ index 0000000000..dfaaa847cb
+#endif
+#endif
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 9c76780181..dd6430ece8 100644
index 79761f6d2..e9435c693 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -87,6 +87,12 @@
@ -255,7 +254,7 @@ index 9c76780181..dd6430ece8 100644
#include <stdlib.h>
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
index a89b5144f6..4d6cc0bdf9 100644
index 301e3476d..19f2cc230 100644
--- a/src/kadmin/dbutil/dump.c
+++ b/src/kadmin/dbutil/dump.c
@@ -148,12 +148,21 @@ create_ofile(char *ofile, char **tmpname)
@ -290,10 +289,10 @@ index a89b5144f6..4d6cc0bdf9 100644
com_err(progname, errno, _("while creating 'ok' file, '%s'"), file_ok);
goto cleanup;
diff --git a/src/kdc/main.c b/src/kdc/main.c
index bfdfef5c48..b43fe9a082 100644
index fdcd694d7..1ede4bf2f 100644
--- a/src/kdc/main.c
+++ b/src/kdc/main.c
@@ -844,7 +844,7 @@ write_pid_file(const char *path)
@@ -872,7 +872,7 @@ write_pid_file(const char *path)
FILE *file;
unsigned long pid;
@ -303,10 +302,10 @@ index bfdfef5c48..b43fe9a082 100644
return errno;
pid = (unsigned long) getpid();
diff --git a/src/kprop/kpropd.c b/src/kprop/kpropd.c
index aa3c81ea30..cb9785aaeb 100644
index 5622d56e1..356e3e0e6 100644
--- a/src/kprop/kpropd.c
+++ b/src/kprop/kpropd.c
@@ -488,6 +488,9 @@ doit(int fd)
@@ -487,6 +487,9 @@ doit(int fd)
krb5_enctype etype;
int database_fd;
char host[INET6_ADDRSTRLEN + 1];
@ -316,7 +315,7 @@ index aa3c81ea30..cb9785aaeb 100644
signal_wrapper(SIGALRM, alarm_handler);
alarm(params.iprop_resync_timeout);
@@ -543,9 +546,15 @@ doit(int fd)
@@ -542,9 +545,15 @@ doit(int fd)
free(name);
exit(1);
}
@ -333,10 +332,10 @@ index aa3c81ea30..cb9785aaeb 100644
KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK);
if (retval) {
diff --git a/src/lib/kadm5/logger.c b/src/lib/kadm5/logger.c
index e14da53790..b879a4049b 100644
index c6885edf2..9aec3c05e 100644
--- a/src/lib/kadm5/logger.c
+++ b/src/lib/kadm5/logger.c
@@ -310,7 +310,7 @@ krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do
@@ -309,7 +309,7 @@ krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do
*/
append = (cp[4] == ':') ? O_APPEND : 0;
if (append || cp[4] == '=') {
@ -345,7 +344,7 @@ index e14da53790..b879a4049b 100644
S_IRUSR | S_IWUSR | S_IRGRP);
if (fd != -1)
f = fdopen(fd, append ? "a" : "w");
@@ -777,7 +777,7 @@ krb5_klog_reopen(krb5_context kcontext)
@@ -776,7 +776,7 @@ krb5_klog_reopen(krb5_context kcontext)
* In case the old logfile did not get moved out of the
* way, open for append to prevent squashing the old logs.
*/
@ -355,7 +354,7 @@ index e14da53790..b879a4049b 100644
set_cloexec_file(f);
log_control.log_entries[lindex].lfu_filep = f;
diff --git a/src/lib/kdb/kdb_log.c b/src/lib/kdb/kdb_log.c
index 2659a25018..e9b95fce59 100644
index 2659a2501..e9b95fce5 100644
--- a/src/lib/kdb/kdb_log.c
+++ b/src/lib/kdb/kdb_log.c
@@ -480,7 +480,7 @@ ulog_map(krb5_context context, const char *logname, uint32_t ulogentries)
@ -368,7 +367,7 @@ index 2659a25018..e9b95fce59 100644
retval = errno;
goto cleanup;
diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c
index 1da40b51d0..f3ab7340a6 100644
index 7b100a0ec..5683a0433 100644
--- a/src/lib/krb5/ccache/cc_dir.c
+++ b/src/lib/krb5/ccache/cc_dir.c
@@ -183,10 +183,19 @@ write_primary_file(const char *primary_path, const char *contents)
@ -418,7 +417,7 @@ index 1da40b51d0..f3ab7340a6 100644
_("Credential cache directory %s does not exist"),
dirname);
diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c
index e510211fc5..f3ea28c8ec 100644
index 021c94398..aaf573439 100644
--- a/src/lib/krb5/keytab/kt_file.c
+++ b/src/lib/krb5/keytab/kt_file.c
@@ -735,14 +735,14 @@ krb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode)
@ -439,10 +438,10 @@ index e510211fc5..f3ea28c8ec 100644
goto report_errno;
writevno = 1;
diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
index 4cbbbb270a..c4058ddc96 100644
index 7073459f0..e9b99f4ca 100644
--- a/src/lib/krb5/os/trace.c
+++ b/src/lib/krb5/os/trace.c
@@ -460,7 +460,7 @@ krb5_set_trace_filename(krb5_context context, const char *filename)
@@ -458,7 +458,7 @@ krb5_set_trace_filename(krb5_context context, const char *filename)
fd = malloc(sizeof(*fd));
if (fd == NULL)
return ENOMEM;
@ -452,7 +451,7 @@ index 4cbbbb270a..c4058ddc96 100644
free(fd);
return errno;
diff --git a/src/plugins/kdb/db2/adb_openclose.c b/src/plugins/kdb/db2/adb_openclose.c
index 9a506e9d44..f92ab47143 100644
index 7db30a33b..2b9d01921 100644
--- a/src/plugins/kdb/db2/adb_openclose.c
+++ b/src/plugins/kdb/db2/adb_openclose.c
@@ -152,7 +152,7 @@ osa_adb_init_db(osa_adb_db_t *dbp, char *filename, char *lockfilename,
@ -465,7 +464,7 @@ index 9a506e9d44..f92ab47143 100644
* maybe someone took away write permission so we could only
* get shared locks?
diff --git a/src/plugins/kdb/db2/kdb_db2.c b/src/plugins/kdb/db2/kdb_db2.c
index 2c163d91cc..9a344a603e 100644
index 5106a5c99..e481e8121 100644
--- a/src/plugins/kdb/db2/kdb_db2.c
+++ b/src/plugins/kdb/db2/kdb_db2.c
@@ -694,8 +694,8 @@ ctx_create_db(krb5_context context, krb5_db2_context *dbc)
@ -480,7 +479,7 @@ index 2c163d91cc..9a344a603e 100644
retval = errno;
goto cleanup;
diff --git a/src/plugins/kdb/db2/libdb2/btree/bt_open.c b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
index 2977b17f3a..d5809a5a93 100644
index 2977b17f3..d5809a5a9 100644
--- a/src/plugins/kdb/db2/libdb2/btree/bt_open.c
+++ b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
@@ -60,6 +60,7 @@ static char sccsid[] = "@(#)bt_open.c 8.11 (Berkeley) 11/2/95";
@ -501,7 +500,7 @@ index 2977b17f3a..d5809a5a93 100644
} else {
diff --git a/src/plugins/kdb/db2/libdb2/hash/hash.c b/src/plugins/kdb/db2/libdb2/hash/hash.c
index 862dbb1640..686a960c96 100644
index 862dbb164..686a960c9 100644
--- a/src/plugins/kdb/db2/libdb2/hash/hash.c
+++ b/src/plugins/kdb/db2/libdb2/hash/hash.c
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)hash.c 8.12 (Berkeley) 11/7/95";
@ -522,7 +521,7 @@ index 862dbb1640..686a960c96 100644
(void)fcntl(hashp->fp, F_SETFD, 1);
}
diff --git a/src/plugins/kdb/db2/libdb2/recno/rec_open.c b/src/plugins/kdb/db2/libdb2/recno/rec_open.c
index d8b26e7011..b0daa7c021 100644
index d8b26e701..b0daa7c02 100644
--- a/src/plugins/kdb/db2/libdb2/recno/rec_open.c
+++ b/src/plugins/kdb/db2/libdb2/recno/rec_open.c
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)rec_open.c 8.12 (Berkeley) 11/18/94";
@ -544,7 +543,7 @@ index d8b26e7011..b0daa7c021 100644
if (fname != NULL && fcntl(rfd, F_SETFD, 1) == -1) {
diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
index e87688d666..30f7c00ab5 100644
index b92cb58c7..0a95101ad 100644
--- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
+++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
@@ -190,7 +190,7 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
@ -581,7 +580,7 @@ index e87688d666..30f7c00ab5 100644
if (newfile == NULL) {
com_err(me, errno, _("Error creating file %s"), tmp_file);
diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c
index aa951df05f..79f9500f69 100644
index aa951df05..79f9500f6 100644
--- a/src/util/profile/prof_file.c
+++ b/src/util/profile/prof_file.c
@@ -33,6 +33,7 @@
@ -602,7 +601,7 @@ index aa951df05f..79f9500f69 100644
retval = errno;
if (retval == 0)
diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in
index 86d5a950a6..1052d53a1e 100644
index 86d5a950a..1052d53a1 100644
--- a/src/util/support/Makefile.in
+++ b/src/util/support/Makefile.in
@@ -74,6 +74,7 @@ IPC_SYMS= \
@ -624,10 +623,10 @@ index 86d5a950a6..1052d53a1e 100644
diff --git a/src/util/support/selinux.c b/src/util/support/selinux.c
new file mode 100644
index 0000000000..807d039da3
index 000000000..6d41f3244
--- /dev/null
+++ b/src/util/support/selinux.c
@@ -0,0 +1,405 @@
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2007,2008,2009,2011,2012,2013,2016 Red Hat, Inc. All Rights Reserved.
+ *
@ -726,16 +725,17 @@ index 0000000000..807d039da3
+ }
+}
+
+static char *
+static security_context_t
+push_fscreatecon(const char *pathname, mode_t mode)
+{
+ char *previous, *configuredsc, *currentsc, *genpath;
+ const char *derivedsc, *fullpath, *currentuser;
+ security_context_t previous, configuredsc, currentsc, derivedsc;
+ context_t current, derived;
+ const char *fullpath, *currentuser;
+ char *genpath;
+
+ previous = configuredsc = currentsc = genpath = NULL;
+ derivedsc = NULL;
+ previous = configuredsc = currentsc = derivedsc = NULL;
+ current = derived = NULL;
+ genpath = NULL;
+
+ fullpath = pathname;
+
@ -863,7 +863,7 @@ index 0000000000..807d039da3
+}
+
+static void
+pop_fscreatecon(char *previous)
+pop_fscreatecon(security_context_t previous)
+{
+ if (!is_selinux_enabled()) {
+ return;
@ -917,7 +917,7 @@ index 0000000000..807d039da3
+{
+ FILE *fp;
+ int errno_save;
+ char *ctx;
+ security_context_t ctx;
+
+ if ((strcmp(mode, "r") == 0) ||
+ (strcmp(mode, "rb") == 0)) {
@ -943,7 +943,7 @@ index 0000000000..807d039da3
+{
+ int fd;
+ int errno_save;
+ char *ctx;
+ security_context_t ctx;
+
+ k5_once(&labeled_once, label_mutex_init);
+ k5_mutex_lock(&labeled_mutex);
@ -964,7 +964,7 @@ index 0000000000..807d039da3
+{
+ int ret;
+ int errno_save;
+ char *ctx;
+ security_context_t ctx;
+
+ k5_once(&labeled_once, label_mutex_init);
+ k5_mutex_lock(&labeled_mutex);
@ -985,7 +985,7 @@ index 0000000000..807d039da3
+{
+ int ret;
+ int errno_save;
+ char *ctx;
+ security_context_t ctx;
+
+ k5_once(&labeled_once, label_mutex_init);
+ k5_mutex_lock(&labeled_mutex);
@ -1006,7 +1006,7 @@ index 0000000000..807d039da3
+{
+ int fd;
+ int errno_save;
+ char *ctx;
+ security_context_t ctx;
+ mode_t mode;
+ va_list ap;
+
@ -1033,6 +1033,3 @@ index 0000000000..807d039da3
+}
+
+#endif /* USE_SELINUX */
--
2.41.0

@ -0,0 +1,140 @@
From 8ded82fb279198f3fa20fb7c836e77290e7bc6f6 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 +
5 files changed, 66 insertions(+), 1 deletion(-)
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 12a1d441b8..dbe87561c5 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -8392,6 +8392,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 28784ec67c..ac94e0c236 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -508,6 +508,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
--
2.40.1

@ -0,0 +1,342 @@
From cc1cd235a6a8c066531a17d5773f601455bedb52 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 31 Mar 2022 18:24:39 +0200
Subject: [PATCH] Use newly enforced dejagnu path naming convention
Since version 1.6.3, dejagnu started to enforce a naming convention that
was already in place, but not mandatory: dejagnu test directories have
to be named "testsuite". If they don't implicit relative sub-paths
resolution (e.g. "lib", "config") is not forking.
This commit renames kadm5 library's unit tests directory to match this
requirement.
Resolves: rhbz#2070879
Signed-off-by: Julien Rische <jrische@redhat.com>
---
src/configure.ac | 2 +-
src/lib/kadm5/Makefile.in | 2 +-
.../{unit-test => testsuite}/Makefile.in | 28 +++++++++----------
.../api.2/crte-policy.exp | 0
.../api.2/get-policy.exp | 0
.../api.2/mod-policy.exp | 0
.../api.current/chpass-principal-v2.exp | 0
.../api.current/chpass-principal.exp | 0
.../api.current/crte-policy.exp | 0
.../api.current/crte-principal.exp | 0
.../api.current/destroy.exp | 0
.../api.current/dlte-policy.exp | 0
.../api.current/dlte-principal.exp | 0
.../api.current/get-policy.exp | 0
.../api.current/get-principal-v2.exp | 0
.../api.current/get-principal.exp | 0
.../api.current/init-v2.exp | 0
.../api.current/init.exp | 0
.../api.current/mod-policy.exp | 0
.../api.current/mod-principal-v2.exp | 0
.../api.current/mod-principal.exp | 0
.../api.current/randkey-principal-v2.exp | 0
.../api.current/randkey-principal.exp | 0
.../{unit-test => testsuite}/config/unix.exp | 0
src/lib/kadm5/{unit-test => testsuite}/deps | 0
.../{unit-test => testsuite}/destroy-test.c | 0
.../diff-files/destroy-1 | 0
.../diff-files/no-diffs | 0
.../{unit-test => testsuite}/handle-test.c | 0
.../{unit-test => testsuite}/init-test.c | 0
.../{unit-test => testsuite}/iter-test.c | 0
.../kadm5/{unit-test => testsuite}/lib/lib.t | 2 +-
.../{unit-test => testsuite}/lock-test.c | 0
.../{unit-test => testsuite}/randkey-test.c | 0
.../{unit-test => testsuite}/setkey-test.c | 0
.../kadm5/{unit-test => testsuite}/site.exp | 0
36 files changed, 17 insertions(+), 17 deletions(-)
rename src/lib/kadm5/{unit-test => testsuite}/Makefile.in (86%)
rename src/lib/kadm5/{unit-test => testsuite}/api.2/crte-policy.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.2/get-policy.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.2/mod-policy.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/chpass-principal-v2.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/chpass-principal.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/crte-policy.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/crte-principal.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/destroy.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/dlte-policy.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/dlte-principal.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/get-policy.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/get-principal-v2.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/get-principal.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/init-v2.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/init.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/mod-policy.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/mod-principal-v2.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/mod-principal.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/randkey-principal-v2.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/api.current/randkey-principal.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/config/unix.exp (100%)
rename src/lib/kadm5/{unit-test => testsuite}/deps (100%)
rename src/lib/kadm5/{unit-test => testsuite}/destroy-test.c (100%)
rename src/lib/kadm5/{unit-test => testsuite}/diff-files/destroy-1 (100%)
rename src/lib/kadm5/{unit-test => testsuite}/diff-files/no-diffs (100%)
rename src/lib/kadm5/{unit-test => testsuite}/handle-test.c (100%)
rename src/lib/kadm5/{unit-test => testsuite}/init-test.c (100%)
rename src/lib/kadm5/{unit-test => testsuite}/iter-test.c (100%)
rename src/lib/kadm5/{unit-test => testsuite}/lib/lib.t (99%)
rename src/lib/kadm5/{unit-test => testsuite}/lock-test.c (100%)
rename src/lib/kadm5/{unit-test => testsuite}/randkey-test.c (100%)
rename src/lib/kadm5/{unit-test => testsuite}/setkey-test.c (100%)
rename src/lib/kadm5/{unit-test => testsuite}/site.exp (100%)
diff --git a/src/configure.ac b/src/configure.ac
index 29be532cb..37e36b76d 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1499,7 +1499,7 @@ V5_AC_OUTPUT_MAKEFILE(.
lib/rpc lib/rpc/unit-test
- lib/kadm5 lib/kadm5/clnt lib/kadm5/srv lib/kadm5/unit-test
+ lib/kadm5 lib/kadm5/clnt lib/kadm5/srv lib/kadm5/testsuite
lib/krad
lib/apputils
diff --git a/src/lib/kadm5/Makefile.in b/src/lib/kadm5/Makefile.in
index c4eaad38d..76fc4b548 100644
--- a/src/lib/kadm5/Makefile.in
+++ b/src/lib/kadm5/Makefile.in
@@ -1,6 +1,6 @@
mydir=lib$(S)kadm5
BUILDTOP=$(REL)..$(S)..
-SUBDIRS = clnt srv unit-test
+SUBDIRS = clnt srv testsuite
##DOSBUILDTOP = ..\..
diff --git a/src/lib/kadm5/unit-test/Makefile.in b/src/lib/kadm5/testsuite/Makefile.in
similarity index 86%
rename from src/lib/kadm5/unit-test/Makefile.in
rename to src/lib/kadm5/testsuite/Makefile.in
index 68fa097ff..5a55b786b 100644
--- a/src/lib/kadm5/unit-test/Makefile.in
+++ b/src/lib/kadm5/testsuite/Makefile.in
@@ -1,4 +1,4 @@
-mydir=lib$(S)kadm5$(S)unit-test
+mydir=lib$(S)kadm5$(S)testsuite
BUILDTOP=$(REL)..$(S)..$(S)..
KDB_DEP_LIB=$(DL_LIB) $(THREAD_LINKOPTS)
@@ -61,7 +61,7 @@ runenv.exp: Makefile
eval echo "set env\($$i\) \$$$$i"; done > runenv.exp
#
-# The unit-test targets
+# The testsuite targets
#
check: check-@DO_TEST@
@@ -72,13 +72,13 @@ check-:
@echo "+++ Either tcl, runtest, or Perl is unavailable."
@echo "+++"
-check-ok unit-test: unit-test-client unit-test-server
+check-ok testsuite: testsuite-client testsuite-server
-unit-test-client: unit-test-client-setup unit-test-client-body \
- unit-test-client-cleanup
+testsuite-client: testsuite-client-setup testsuite-client-body \
+ testsuite-client-cleanup
-unit-test-server: unit-test-server-setup unit-test-server-body \
- unit-test-server-cleanup
+testsuite-server: testsuite-server-setup testsuite-server-body \
+ testsuite-server-cleanup
test-randkey: randkey-test
$(ENV_SETUP) $(VALGRIND) ./randkey-test
@@ -98,19 +98,19 @@ test-destroy: destroy-test
test-setkey-client: client-setkey-test
$(ENV_SETUP) $(VALGRIND) ./client-setkey-test testkeys admin admin
-unit-test-client-setup: runenv.sh
+testsuite-client-setup: runenv.sh
$(ENV_SETUP) $(VALGRIND) $(START_SERVERS)
-unit-test-client-cleanup:
+testsuite-client-cleanup:
$(ENV_SETUP) $(STOP_SERVERS)
-unit-test-server-setup: runenv.sh
+testsuite-server-setup: runenv.sh
$(ENV_SETUP) $(VALGRIND) $(START_SERVERS_LOCAL)
-unit-test-server-cleanup:
+testsuite-server-cleanup:
$(ENV_SETUP) $(STOP_SERVERS_LOCAL)
-unit-test-client-body: site.exp test-noauth test-destroy test-handle-client \
+testsuite-client-body: site.exp test-noauth test-destroy test-handle-client \
test-setkey-client runenv.exp
$(ENV_SETUP) $(RUNTEST) --tool api RPC=1 API=$(CLNTTCL) \
KINIT=$(BUILDTOP)/clients/kinit/kinit \
@@ -121,7 +121,7 @@ unit-test-client-body: site.exp test-noauth test-destroy test-handle-client \
-mv api.log capi.log
-mv api.sum capi.sum
-unit-test-server-body: site.exp test-handle-server lock-test
+testsuite-server-body: site.exp test-handle-server lock-test
$(ENV_SETUP) $(RUNTEST) --tool api RPC=0 API=$(SRVTCL) \
LOCKTEST=./lock-test \
KADMIN_LOCAL=$(BUILDTOP)/kadmin/cli/kadmin.local \
@@ -140,4 +140,4 @@ clean:
$(RM) lock-test lock-test.o
$(RM) server-iter-test iter-test.o
$(RM) server-setkey-test client-setkey-test setkey-test.o
- $(RM) *.log *.plog *.sum *.psum unit-test-log.* runenv.exp
+ $(RM) *.log *.plog *.sum *.psum testsuite-log.* runenv.exp
diff --git a/src/lib/kadm5/unit-test/api.2/crte-policy.exp b/src/lib/kadm5/testsuite/api.2/crte-policy.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.2/crte-policy.exp
rename to src/lib/kadm5/testsuite/api.2/crte-policy.exp
diff --git a/src/lib/kadm5/unit-test/api.2/get-policy.exp b/src/lib/kadm5/testsuite/api.2/get-policy.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.2/get-policy.exp
rename to src/lib/kadm5/testsuite/api.2/get-policy.exp
diff --git a/src/lib/kadm5/unit-test/api.2/mod-policy.exp b/src/lib/kadm5/testsuite/api.2/mod-policy.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.2/mod-policy.exp
rename to src/lib/kadm5/testsuite/api.2/mod-policy.exp
diff --git a/src/lib/kadm5/unit-test/api.current/chpass-principal-v2.exp b/src/lib/kadm5/testsuite/api.current/chpass-principal-v2.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/chpass-principal-v2.exp
rename to src/lib/kadm5/testsuite/api.current/chpass-principal-v2.exp
diff --git a/src/lib/kadm5/unit-test/api.current/chpass-principal.exp b/src/lib/kadm5/testsuite/api.current/chpass-principal.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/chpass-principal.exp
rename to src/lib/kadm5/testsuite/api.current/chpass-principal.exp
diff --git a/src/lib/kadm5/unit-test/api.current/crte-policy.exp b/src/lib/kadm5/testsuite/api.current/crte-policy.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/crte-policy.exp
rename to src/lib/kadm5/testsuite/api.current/crte-policy.exp
diff --git a/src/lib/kadm5/unit-test/api.current/crte-principal.exp b/src/lib/kadm5/testsuite/api.current/crte-principal.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/crte-principal.exp
rename to src/lib/kadm5/testsuite/api.current/crte-principal.exp
diff --git a/src/lib/kadm5/unit-test/api.current/destroy.exp b/src/lib/kadm5/testsuite/api.current/destroy.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/destroy.exp
rename to src/lib/kadm5/testsuite/api.current/destroy.exp
diff --git a/src/lib/kadm5/unit-test/api.current/dlte-policy.exp b/src/lib/kadm5/testsuite/api.current/dlte-policy.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/dlte-policy.exp
rename to src/lib/kadm5/testsuite/api.current/dlte-policy.exp
diff --git a/src/lib/kadm5/unit-test/api.current/dlte-principal.exp b/src/lib/kadm5/testsuite/api.current/dlte-principal.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/dlte-principal.exp
rename to src/lib/kadm5/testsuite/api.current/dlte-principal.exp
diff --git a/src/lib/kadm5/unit-test/api.current/get-policy.exp b/src/lib/kadm5/testsuite/api.current/get-policy.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/get-policy.exp
rename to src/lib/kadm5/testsuite/api.current/get-policy.exp
diff --git a/src/lib/kadm5/unit-test/api.current/get-principal-v2.exp b/src/lib/kadm5/testsuite/api.current/get-principal-v2.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/get-principal-v2.exp
rename to src/lib/kadm5/testsuite/api.current/get-principal-v2.exp
diff --git a/src/lib/kadm5/unit-test/api.current/get-principal.exp b/src/lib/kadm5/testsuite/api.current/get-principal.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/get-principal.exp
rename to src/lib/kadm5/testsuite/api.current/get-principal.exp
diff --git a/src/lib/kadm5/unit-test/api.current/init-v2.exp b/src/lib/kadm5/testsuite/api.current/init-v2.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/init-v2.exp
rename to src/lib/kadm5/testsuite/api.current/init-v2.exp
diff --git a/src/lib/kadm5/unit-test/api.current/init.exp b/src/lib/kadm5/testsuite/api.current/init.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/init.exp
rename to src/lib/kadm5/testsuite/api.current/init.exp
diff --git a/src/lib/kadm5/unit-test/api.current/mod-policy.exp b/src/lib/kadm5/testsuite/api.current/mod-policy.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/mod-policy.exp
rename to src/lib/kadm5/testsuite/api.current/mod-policy.exp
diff --git a/src/lib/kadm5/unit-test/api.current/mod-principal-v2.exp b/src/lib/kadm5/testsuite/api.current/mod-principal-v2.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/mod-principal-v2.exp
rename to src/lib/kadm5/testsuite/api.current/mod-principal-v2.exp
diff --git a/src/lib/kadm5/unit-test/api.current/mod-principal.exp b/src/lib/kadm5/testsuite/api.current/mod-principal.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/mod-principal.exp
rename to src/lib/kadm5/testsuite/api.current/mod-principal.exp
diff --git a/src/lib/kadm5/unit-test/api.current/randkey-principal-v2.exp b/src/lib/kadm5/testsuite/api.current/randkey-principal-v2.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/randkey-principal-v2.exp
rename to src/lib/kadm5/testsuite/api.current/randkey-principal-v2.exp
diff --git a/src/lib/kadm5/unit-test/api.current/randkey-principal.exp b/src/lib/kadm5/testsuite/api.current/randkey-principal.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/api.current/randkey-principal.exp
rename to src/lib/kadm5/testsuite/api.current/randkey-principal.exp
diff --git a/src/lib/kadm5/unit-test/config/unix.exp b/src/lib/kadm5/testsuite/config/unix.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/config/unix.exp
rename to src/lib/kadm5/testsuite/config/unix.exp
diff --git a/src/lib/kadm5/unit-test/deps b/src/lib/kadm5/testsuite/deps
similarity index 100%
rename from src/lib/kadm5/unit-test/deps
rename to src/lib/kadm5/testsuite/deps
diff --git a/src/lib/kadm5/unit-test/destroy-test.c b/src/lib/kadm5/testsuite/destroy-test.c
similarity index 100%
rename from src/lib/kadm5/unit-test/destroy-test.c
rename to src/lib/kadm5/testsuite/destroy-test.c
diff --git a/src/lib/kadm5/unit-test/diff-files/destroy-1 b/src/lib/kadm5/testsuite/diff-files/destroy-1
similarity index 100%
rename from src/lib/kadm5/unit-test/diff-files/destroy-1
rename to src/lib/kadm5/testsuite/diff-files/destroy-1
diff --git a/src/lib/kadm5/unit-test/diff-files/no-diffs b/src/lib/kadm5/testsuite/diff-files/no-diffs
similarity index 100%
rename from src/lib/kadm5/unit-test/diff-files/no-diffs
rename to src/lib/kadm5/testsuite/diff-files/no-diffs
diff --git a/src/lib/kadm5/unit-test/handle-test.c b/src/lib/kadm5/testsuite/handle-test.c
similarity index 100%
rename from src/lib/kadm5/unit-test/handle-test.c
rename to src/lib/kadm5/testsuite/handle-test.c
diff --git a/src/lib/kadm5/unit-test/init-test.c b/src/lib/kadm5/testsuite/init-test.c
similarity index 100%
rename from src/lib/kadm5/unit-test/init-test.c
rename to src/lib/kadm5/testsuite/init-test.c
diff --git a/src/lib/kadm5/unit-test/iter-test.c b/src/lib/kadm5/testsuite/iter-test.c
similarity index 100%
rename from src/lib/kadm5/unit-test/iter-test.c
rename to src/lib/kadm5/testsuite/iter-test.c
diff --git a/src/lib/kadm5/unit-test/lib/lib.t b/src/lib/kadm5/testsuite/lib/lib.t
similarity index 99%
rename from src/lib/kadm5/unit-test/lib/lib.t
rename to src/lib/kadm5/testsuite/lib/lib.t
index 3444775cf..327946849 100644
--- a/src/lib/kadm5/unit-test/lib/lib.t
+++ b/src/lib/kadm5/testsuite/lib/lib.t
@@ -226,7 +226,7 @@ proc end_dump_compare {name} {
global RPC
if { ! $RPC } {
-# set file $TOP/admin/lib/unit-test/diff-files/$name
+# set file $TOP/admin/lib/testsuite/diff-files/$name
# exec $env(SIMPLE_DUMP) > /tmp/dump.after
# exec $env(COMPARE_DUMP) /tmp/dump.before /tmp/dump.after $file
}
diff --git a/src/lib/kadm5/unit-test/lock-test.c b/src/lib/kadm5/testsuite/lock-test.c
similarity index 100%
rename from src/lib/kadm5/unit-test/lock-test.c
rename to src/lib/kadm5/testsuite/lock-test.c
diff --git a/src/lib/kadm5/unit-test/randkey-test.c b/src/lib/kadm5/testsuite/randkey-test.c
similarity index 100%
rename from src/lib/kadm5/unit-test/randkey-test.c
rename to src/lib/kadm5/testsuite/randkey-test.c
diff --git a/src/lib/kadm5/unit-test/setkey-test.c b/src/lib/kadm5/testsuite/setkey-test.c
similarity index 100%
rename from src/lib/kadm5/unit-test/setkey-test.c
rename to src/lib/kadm5/testsuite/setkey-test.c
diff --git a/src/lib/kadm5/unit-test/site.exp b/src/lib/kadm5/testsuite/site.exp
similarity index 100%
rename from src/lib/kadm5/unit-test/site.exp
rename to src/lib/kadm5/testsuite/site.exp
--
2.35.1

@ -1,4 +1,4 @@
From 780db3e904ada1946b0d1dce04c8daa74273c7b6 Mon Sep 17 00:00:00 2001
From 7f382fc40e082416e90f1e80c9fd0c91afa5baf7 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:49:25 -0400
Subject: [PATCH] [downstream] fix debuginfo with y.tab.c
@ -8,13 +8,14 @@ them. It would be more elegant at the end to use symbolic links, but that
could mess up people working in the tree on other things.
Last-updated: krb5-1.9
(cherry picked from commit f4002f246332695d8ea12ec803139fcac18fbba2)
---
src/kadmin/cli/Makefile.in | 5 +++++
src/plugins/kdb/ldap/ldap_util/Makefile.in | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/kadmin/cli/Makefile.in b/src/kadmin/cli/Makefile.in
index adfea6e2b5..d1327e400b 100644
index adfea6e2b..d1327e400 100644
--- a/src/kadmin/cli/Makefile.in
+++ b/src/kadmin/cli/Makefile.in
@@ -37,3 +37,8 @@ clean-unix::
@ -27,7 +28,7 @@ index adfea6e2b5..d1327e400b 100644
+ $(YACC.y) $<
+ $(CP) y.tab.c $@
diff --git a/src/plugins/kdb/ldap/ldap_util/Makefile.in b/src/plugins/kdb/ldap/ldap_util/Makefile.in
index 8669c2436c..a22f23c02c 100644
index 8669c2436..a22f23c02 100644
--- a/src/plugins/kdb/ldap/ldap_util/Makefile.in
+++ b/src/plugins/kdb/ldap/ldap_util/Makefile.in
@@ -20,7 +20,7 @@ $(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIB) $(GETDATE)
@ -39,6 +40,3 @@ index 8669c2436c..a22f23c02c 100644
install:
$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
--
2.41.0

@ -1,4 +1,4 @@
From d7be72b066a9b07f0426780c7931614eddf9dd9e Mon Sep 17 00:00:00 2001
From 664bdd73b620f00d42e36e3888805fe0f035c8ee Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:29:58 -0400
Subject: [PATCH] [downstream] ksu pam integration
@ -18,6 +18,7 @@ and session management before dropping privileges, and to apply on top of
changes we're proposing for how it handles cache collections.
Last-updated: krb5-1.18-beta1
(cherry picked from commit a7322a84657752c886c317a6994a9fc7a4a70ca5)
---
src/aclocal.m4 | 69 +++++++
src/clients/ksu/Makefile.in | 8 +-
@ -30,10 +31,10 @@ Last-updated: krb5-1.18-beta1
create mode 100644 src/clients/ksu/pam.h
diff --git a/src/aclocal.m4 b/src/aclocal.m4
index 3d66a876b3..ce3c5a9bac 100644
index 2394f7e33..830203683 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -1458,3 +1458,72 @@ if test "$with_ldap" = yes; then
@@ -1675,3 +1675,72 @@ if test "$with_ldap" = yes; then
OPENLDAP_PLUGIN=yes
fi
])dnl
@ -107,7 +108,7 @@ index 3d66a876b3..ce3c5a9bac 100644
+])dnl
+
diff --git a/src/clients/ksu/Makefile.in b/src/clients/ksu/Makefile.in
index 8b4edce4d8..9d58f29b5d 100644
index 8b4edce4d..9d58f29b5 100644
--- a/src/clients/ksu/Makefile.in
+++ b/src/clients/ksu/Makefile.in
@@ -3,12 +3,14 @@ BUILDTOP=$(REL)..$(S)..
@ -145,11 +146,11 @@ index 8b4edce4d8..9d58f29b5d 100644
clean:
$(RM) ksu
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
index af12861729..931f054041 100644
index 57c349200..508242e0e 100644
--- a/src/clients/ksu/main.c
+++ b/src/clients/ksu/main.c
@@ -26,6 +26,7 @@
* KSU was written by: Ari Medvinsky, ari@isi.edu
* KSU was writen by: Ari Medvinsky, ari@isi.edu
*/
+#include "autoconf.h"
@ -303,7 +304,7 @@ index af12861729..931f054041 100644
}
diff --git a/src/clients/ksu/pam.c b/src/clients/ksu/pam.c
new file mode 100644
index 0000000000..cbfe487047
index 000000000..cbfe48704
--- /dev/null
+++ b/src/clients/ksu/pam.c
@@ -0,0 +1,389 @@
@ -698,7 +699,7 @@ index 0000000000..cbfe487047
+#endif
diff --git a/src/clients/ksu/pam.h b/src/clients/ksu/pam.h
new file mode 100644
index 0000000000..0ab76569cb
index 000000000..0ab76569c
--- /dev/null
+++ b/src/clients/ksu/pam.h
@@ -0,0 +1,57 @@
@ -760,10 +761,10 @@ index 0000000000..0ab76569cb
+void appl_pam_cleanup(void);
+#endif
diff --git a/src/configure.ac b/src/configure.ac
index 77be7a2025..587221936e 100644
index 234f4281c..d1f576124 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1399,6 +1399,8 @@ AC_SUBST([VERTO_VERSION])
@@ -1390,6 +1390,8 @@ AC_SUBST([VERTO_VERSION])
AC_PATH_PROG(GROFF, groff)
@ -772,6 +773,3 @@ index 77be7a2025..587221936e 100644
# Make localedir work in autoconf 2.5x.
if test "${localedir+set}" != set; then
localedir='$(datadir)/locale'
--
2.41.0

@ -0,0 +1,25 @@
From 0a164c9c53a6f8ce20cfe5c6ef94ae5a2c2e9e28 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:46:21 -0400
Subject: [PATCH] [downstream] netlib and dns
We want to be able to use --with-netlib and --enable-dns at the same time.
Last-updated: krb5-1.3.1
(cherry picked from commit 355dd481511af4d517ee540854f95a6fb12116a9)
---
src/aclocal.m4 | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/aclocal.m4 b/src/aclocal.m4
index 6796fec53..c4358988a 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -724,6 +724,7 @@ AC_HELP_STRING([--with-netlib=LIBS], use user defined resolver library),
LIBS="$LIBS $withval"
AC_MSG_RESULT("netlib will use \'$withval\'")
fi
+ KRB5_AC_ENABLE_DNS
],dnl
[AC_LIBRARY_NET]
)])dnl

@ -6,9 +6,9 @@ AssertPathExists=!/var/kerberos/krb5kdc/kpropd.acl
[Service]
Type=forking
PIDFile=/run/kadmind.pid
PIDFile=/var/run/kadmind.pid
EnvironmentFile=-/etc/sysconfig/kadmin
ExecStart=/usr/sbin/kadmind -P /run/kadmind.pid $KADMIND_ARGS
ExecStart=/usr/sbin/kadmind -P /var/run/kadmind.pid $KADMIND_ARGS
ExecReload=/bin/kill -HUP $MAINPID
[Install]

@ -4,6 +4,6 @@
monthly
rotate 12
postrotate
systemctl reload kadmin.service || true
/bin/kill -HUP `cat /var/run/kadmind.pid 2>/dev/null` 2> /dev/null || true
endscript
}

@ -5,12 +5,9 @@
[realms]
EXAMPLE.COM = {
master_key_type = aes256-cts-hmac-sha384-192
#master_key_type = aes256-cts
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
default_principal_flags = +preauth
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
supported_enctypes = aes256-cts-hmac-sha384-192:normal aes128-cts-hmac-sha256-128:normal aes256-cts-hmac-sha1-96:normal aes128-cts-hmac-sha1-96:normal camellia256-cts-cmac:normal camellia128-cts-cmac:normal arcfour-hmac-md5:normal
# Supported encryption types for FIPS mode:
#supported_enctypes = aes256-cts-hmac-sha384-192:normal aes128-cts-hmac-sha256-128:normal
supported_enctypes = aes256-cts:normal aes128-cts:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal
}

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEExEk8tzn0qJ+YUsvCDLoIV1+Dct8FAl7H9FAACgkQDLoIV1+D
ct+rjxAAqLlDjeExNw1sJyyjaAKzo7vGzK0tFVouMglmmGcyluVwsqu9B2uHw3UC
TIm4bn1rgGtUB5oKWmbeD+hiuoAghLDa6gSrmDDkJfFR+o/K/vE7BGZewrrp7QJ5
jJnEhjuY9O+ZFM/ZNEwHa4/RNG1ga5uJUrfdlNkTUMFje5d1TXvx/ozuSk4bAUTF
nqHuJsyRAuhKcqTOZ9nr5a54me97CbWj7Be6sA7LQVaFDPyWcJCQsBHjFyextTOF
3ewsF7330B3oO8yE9/f+nxFq/x9ot6CctMXZqLzhbvdzcO2GwmwbvXy73ibhvjVU
w9n/zQ1xDjRO0z1wfM54Vq1upQW78+YXA33fEX6od0WBzdiR/o7hfU3arg/WraUy
pVcD9V7jvYhGPpqYwEdRhs4qROhAh/yvebZ+MVe/1Pd8kA4tTXtR+VmVkp21X3cq
+19eTz7actQemfdsUvfcL8guub0Mea/l+1l3cEHl20FOEeZ8RjpPMisYS9IrJ52O
3lro26vYFSWS4+U9j4gwdjuQwLS3xHuPZFwS7aykKGsIQ1r8l5Yb0xorDXXKKLjm
z4DNPaZbxxfcGhDWKTlDudrXEIAGTOD4FC1SJBV3hbqUsv4EH+EJnf92rmVMJ5z/
AmeUKsL02Abl3BjhwaLWmhIwoXIUhcI/5xNsoI6ePCAT2HLyJlE=
=fGT7
-----END PGP SIGNATURE-----

@ -1,16 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEExEk8tzn0qJ+YUsvCDLoIV1+Dct8FAmSsc/kACgkQDLoIV1+D
ct+wPxAArlkJs5WpFIm2JDJXGF82BNw/FEhg+OkWcPHeLMWJF8qO0AxVp8Yq4g1g
qFpTABwY8V2tfr84XQJ6rw7Qq93NjRjFHr1z1tDmCceLisXof6Tu7/RKjHwNmJt8
M3srmsXPlmx/7cXuaYIljJfftun3D/iuEaydWluGb1DZicaU/OsofGhKE8/YEZrN
H0XdIC45raG4O9t6CGjQRcAIv5Z4afCtXH4aaEmLg6E2+aTUyx+czu7nBASCaTyv
s4df8fhbVpdBi6iA6BQJC296Rc1gyDnuxnjyCH8Rj2gTuiI4Oa2dxRPGT3mjksz3
OheYcXK9XGCtUbG22zrxqUuHDA3jF6KKmsVSXnbygB6XSS/c0bqmeDRTQGPksWH6
RJbmlKG9PQ0BavlXRa7Nupaa7f0jblFiduScYujRsyWxi/8YkckedugYyuww59gV
piUwGGRDWldy+JIAYtvzirsfe6Oum0/SKY5wYXyKv0flM95pbfBEw+TzRxmlCQ5J
+i8L9Frr4gTmT576GHB6WzBlOEPf6mRc8jg0DyyUOoDHXyj4MCyJGEJxvcyVV1WX
tJlu0uH1f8pMZx4IQ279PsNFimO/NsdSTefqiVGXA7FWK1EPLc+l9ZBcrLi9KEmJ
7TfVq9cAg6+m2tql+gjAQrfXHUU1mNdPLFMnShYlqHjTle4cQKE=
=AIvQ
-----END PGP SIGNATURE-----

@ -0,0 +1,69 @@
From b2b7729d71e7ab2cde9c73b40b8e972c82a875a2 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 8 Nov 2021 17:48:50 +0100
Subject: [PATCH] Support larger RADIUS attributes in libkrad
In kr_attrset_decode(), explicitly treat the length byte as unsigned.
Otherwise attributes longer than 125 characters will be rejected with
EBADMSG.
Add a 253-character-long NAS-Identifier attribute to the tests to make
sure that attributes with the maximal number of characters are working
as expected.
[ghudson@mit.edu: used uint8_t cast per current practices; edited
commit message]
ticket: 9036 (new)
---
src/lib/krad/attrset.c | 2 +-
src/lib/krad/t_packet.c | 13 +++++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
index d89982a13..6ec031e32 100644
--- a/src/lib/krad/attrset.c
+++ b/src/lib/krad/attrset.c
@@ -218,7 +218,7 @@ kr_attrset_decode(krb5_context ctx, const krb5_data *in, const char *secret,
for (i = 0; i + 2 < in->length; ) {
type = in->data[i++];
- tmp = make_data(&in->data[i + 1], in->data[i] - 2);
+ tmp = make_data(&in->data[i + 1], (uint8_t)in->data[i] - 2);
i += tmp.length + 1;
retval = (in->length < i) ? EBADMSG : 0;
diff --git a/src/lib/krad/t_packet.c b/src/lib/krad/t_packet.c
index 0a92e9cc2..c22489144 100644
--- a/src/lib/krad/t_packet.c
+++ b/src/lib/krad/t_packet.c
@@ -57,6 +57,14 @@ make_packet(krb5_context ctx, const krb5_data *username,
krb5_error_code retval;
const krb5_data *data;
int i = 0;
+ krb5_data nas_id;
+
+ nas_id = string2data("12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "123");
retval = krad_attrset_new(ctx, &set);
if (retval != 0)
@@ -71,6 +79,11 @@ make_packet(krb5_context ctx, const krb5_data *username,
if (retval != 0)
goto out;
+ retval = krad_attrset_add(set, krad_attr_name2num("NAS-Identifier"),
+ &nas_id);
+ if (retval != 0)
+ goto out;
+
retval = krad_packet_new_request(ctx, "foo",
krad_code_name2num("Access-Request"),
set, iterator, &i, &tmp);
--
2.35.3

@ -0,0 +1,171 @@
From da677b071dadda3700d12d037f5896b166d3546d Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 9 Nov 2021 13:00:43 -0500
Subject: [PATCH] Avoid use after free during libkrad cleanup
libkrad client requests contain a list of references to remotes, with
no back-references or reference counts. To prevent accesses to
dangling references during cleanup, cancel all requests on all remotes
before freeing any remotes.
Remove the code for aging out unused servers. This code was fairly
safe as all requests referencing a remote should have completed or
timed out during an hour of disuse, but in the current design we have
no way to guarantee or check that. The set of addresses we send
RADIUS requests to will generally be small, so aging out servers is
unnecessary.
ticket: 9035 (new)
---
src/lib/krad/client.c | 42 ++++++++++++++---------------------------
src/lib/krad/internal.h | 4 ++++
src/lib/krad/remote.c | 11 ++++++++---
3 files changed, 26 insertions(+), 31 deletions(-)
diff --git a/src/lib/krad/client.c b/src/lib/krad/client.c
index 6365dd1c6..810940afc 100644
--- a/src/lib/krad/client.c
+++ b/src/lib/krad/client.c
@@ -64,7 +64,6 @@ struct request_st {
struct server_st {
krad_remote *serv;
- time_t last;
K5_LIST_ENTRY(server_st) list;
};
@@ -81,15 +80,10 @@ get_server(krad_client *rc, const struct addrinfo *ai, const char *secret,
krad_remote **out)
{
krb5_error_code retval;
- time_t currtime;
server *srv;
- if (time(&currtime) == (time_t)-1)
- return errno;
-
K5_LIST_FOREACH(srv, &rc->servers, list) {
if (kr_remote_equals(srv->serv, ai, secret)) {
- srv->last = currtime;
*out = srv->serv;
return 0;
}
@@ -98,7 +92,6 @@ get_server(krad_client *rc, const struct addrinfo *ai, const char *secret,
srv = calloc(1, sizeof(server));
if (srv == NULL)
return ENOMEM;
- srv->last = currtime;
retval = kr_remote_new(rc->kctx, rc->vctx, ai, secret, &srv->serv);
if (retval != 0) {
@@ -173,28 +166,12 @@ request_new(krad_client *rc, krad_code code, const krad_attrset *attrs,
return 0;
}
-/* Close remotes that haven't been used in a while. */
-static void
-age(struct server_head *head, time_t currtime)
-{
- server *srv, *tmp;
-
- K5_LIST_FOREACH_SAFE(srv, head, list, tmp) {
- if (currtime == (time_t)-1 || currtime - srv->last > 60 * 60) {
- K5_LIST_REMOVE(srv, list);
- kr_remote_free(srv->serv);
- free(srv);
- }
- }
-}
-
/* Handle a response from a server (or related errors). */
static void
on_response(krb5_error_code retval, const krad_packet *reqp,
const krad_packet *rspp, void *data)
{
request *req = data;
- time_t currtime;
size_t i;
/* Do nothing if we are already completed. */
@@ -221,10 +198,6 @@ on_response(krb5_error_code retval, const krad_packet *reqp,
for (i = 0; req->remotes[i].remote != NULL; i++)
kr_remote_cancel(req->remotes[i].remote, req->remotes[i].packet);
- /* Age out servers that haven't been used in a while. */
- if (time(&currtime) != (time_t)-1)
- age(&req->rc->servers, currtime);
-
request_free(req);
}
@@ -247,10 +220,23 @@ krad_client_new(krb5_context kctx, verto_ctx *vctx, krad_client **out)
void
krad_client_free(krad_client *rc)
{
+ server *srv;
+
if (rc == NULL)
return;
- age(&rc->servers, -1);
+ /* Cancel all requests before freeing any remotes, since each request's
+ * callback data may contain references to multiple remotes. */
+ K5_LIST_FOREACH(srv, &rc->servers, list)
+ kr_remote_cancel_all(srv->serv);
+
+ while (!K5_LIST_EMPTY(&rc->servers)) {
+ srv = K5_LIST_FIRST(&rc->servers);
+ K5_LIST_REMOVE(srv, list);
+ kr_remote_free(srv->serv);
+ free(srv);
+ }
+
free(rc);
}
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
index 312dc8258..b086598fb 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -120,6 +120,10 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
void
kr_remote_cancel(krad_remote *rr, const krad_packet *pkt);
+/* Cancel all requests awaiting responses. */
+void
+kr_remote_cancel_all(krad_remote *rr);
+
/* Determine if this remote object refers to the remote resource identified
* by the addrinfo struct and the secret. */
krb5_boolean
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
index 0f90443ce..b5dd8cd19 100644
--- a/src/lib/krad/remote.c
+++ b/src/lib/krad/remote.c
@@ -421,15 +421,20 @@ error:
return retval;
}
+void
+kr_remote_cancel_all(krad_remote *rr)
+{
+ while (!K5_TAILQ_EMPTY(&rr->list))
+ request_finish(K5_TAILQ_FIRST(&rr->list), ECANCELED, NULL);
+}
+
void
kr_remote_free(krad_remote *rr)
{
if (rr == NULL)
return;
- while (!K5_TAILQ_EMPTY(&rr->list))
- request_finish(K5_TAILQ_FIRST(&rr->list), ECANCELED, NULL);
-
+ kr_remote_cancel_all(rr);
free(rr->secret);
if (rr->info != NULL)
free(rr->info->ai_addr);
--
2.35.3

@ -15,8 +15,6 @@ includedir /etc/krb5.conf.d/
rdns = false
pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt
spake_preauth_groups = edwards25519
dns_canonicalize_hostname = fallback
qualify_shortname = ""
# default_realm = EXAMPLE.COM
[realms]

@ -4,6 +4,6 @@
monthly
rotate 12
postrotate
systemctl reload krb5kdc.service || true
/bin/kill -HUP `cat /var/run/krb5kdc.pid 2>/dev/null` 2> /dev/null || true
endscript
}

@ -5,9 +5,9 @@ After=syslog.target network.target network-online.target
[Service]
Type=forking
PIDFile=/run/krb5kdc.pid
PIDFile=/var/run/krb5kdc.pid
EnvironmentFile=-/etc/sysconfig/krb5kdc
ExecStart=/usr/sbin/krb5kdc -P /run/krb5kdc.pid $KRB5KDC_ARGS
ExecStart=/usr/sbin/krb5kdc -P /var/run/krb5kdc.pid $KRB5KDC_ARGS
ExecReload=/bin/kill -HUP $MAINPID
[Install]

@ -0,0 +1,751 @@
From 396ce77f48f758efa090aadd00cd7208e7e97491 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Fri, 15 Nov 2019 20:05:16 +0000
Subject: [PATCH] [rhel] Use backported version of OpenSSL-3 KDF interface
(cherry picked from commit 0e20daf7ccfe50518c89735c3dae2fde08d92325)
---
src/configure.ac | 4 +
src/lib/crypto/krb/derive.c | 356 +++++++++++++-----
.../preauth/pkinit/pkinit_crypto_openssl.c | 257 ++++++++-----
3 files changed, 428 insertions(+), 189 deletions(-)
diff --git a/src/configure.ac b/src/configure.ac
index d4e4da525..29be532cb 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -282,6 +282,10 @@ AC_SUBST(CRYPTO_IMPL)
AC_SUBST(CRYPTO_IMPL_CFLAGS)
AC_SUBST(CRYPTO_IMPL_LIBS)
+AC_CHECK_FUNCS(EVP_KDF_CTX_new_id EVP_KDF_ctrl EVP_KDF_derive,
+ AC_DEFINE(OSSL_KDFS, 1, [Define if using OpenSSL KDFs]),
+ AC_MSG_ERROR([backported OpenSSL KDFs not found]))
+
AC_ARG_WITH([prng-alg],
AC_HELP_STRING([--with-prng-alg=ALG], [use specified PRNG algorithm. @<:@fortuna@:>@]),
[PRNG_ALG=$withval
diff --git a/src/lib/crypto/krb/derive.c b/src/lib/crypto/krb/derive.c
index 6707a7308..915a173dd 100644
--- a/src/lib/crypto/krb/derive.c
+++ b/src/lib/crypto/krb/derive.c
@@ -27,6 +27,13 @@
#include "crypto_int.h"
+#ifdef OSSL_KDFS
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#else
+#error "Refusing to build without OpenSSL KDFs!"
+#endif
+
static krb5_key
find_cached_dkey(struct derived_key *list, const krb5_data *constant)
{
@@ -77,55 +84,193 @@ cleanup:
return ENOMEM;
}
+#ifdef OSSL_KDFS
static krb5_error_code
-derive_random_rfc3961(const struct krb5_enc_provider *enc,
- krb5_key inkey, krb5_data *outrnd,
- const krb5_data *in_constant)
+openssl_kbdkf_counter_hmac(const struct krb5_hash_provider *hash,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *label, const krb5_data *context)
{
- size_t blocksize, keybytes, n;
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
+ EVP_KDF_CTX *ctx = NULL;
+ const EVP_MD *digest;
+
+ if (!strcmp(hash->hash_name, "SHA1"))
+ digest = EVP_sha1();
+ else if (!strcmp(hash->hash_name, "SHA-256"))
+ digest = EVP_sha256();
+ else if (!strcmp(hash->hash_name, "SHA-384"))
+ digest = EVP_sha384();
+ else
+ goto done;
+
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KB);
+ if (!ctx)
+ goto done;
+
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE,
+ EVP_KDF_KB_MAC_TYPE_HMAC) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents,
+ inkey->keyblock.length) != 1 ||
+ (context->length > 0 &&
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_INFO, context->data,
+ context->length) != 1) ||
+ (label->length > 0 &&
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SALT, label->data,
+ label->length) != 1) ||
+ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data,
+ outrnd->length) != 1)
+ goto done;
+
+ ret = 0;
+done:
+ if (ret)
+ zap(outrnd->data, outrnd->length);
+ EVP_KDF_CTX_free(ctx);
+ return ret;
+}
+
+static krb5_error_code
+openssl_kbkdf_feedback_cmac(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
+ EVP_KDF_CTX *ctx = NULL;
+ const EVP_CIPHER *cipher;
+ static unsigned char zeroes[16];
+
+ memset(zeroes, 0, sizeof(zeroes));
+
+ if (enc->keylength == 16)
+ cipher = EVP_camellia_128_cbc();
+ else if (enc->keylength == 32)
+ cipher = EVP_camellia_256_cbc();
+ else
+ goto done;
+
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KB);
+ if (!ctx)
+ goto done;
+
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MODE,
+ EVP_KDF_KB_MODE_FEEDBACK) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE,
+ EVP_KDF_KB_MAC_TYPE_CMAC) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_CIPHER, cipher) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents,
+ inkey->keyblock.length) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SALT, in_constant->data,
+ in_constant->length) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_SEED, zeroes,
+ sizeof(zeroes)) != 1 ||
+ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data,
+ outrnd->length) != 1)
+ goto done;
+
+ ret = 0;
+done:
+ if (ret)
+ zap(outrnd->data, outrnd->length);
+ EVP_KDF_CTX_free(ctx);
+ return ret;
+}
+
+static krb5_error_code
+openssl_krb5kdf(const struct krb5_enc_provider *enc, krb5_key inkey,
+ krb5_data *outrnd, const krb5_data *in_constant)
+{
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
+ EVP_KDF_CTX *ctx = NULL;
+ const EVP_CIPHER *cipher;
+
+ if (inkey->keyblock.length != enc->keylength ||
+ outrnd->length != enc->keybytes) {
+ return KRB5_CRYPTO_INTERNAL;
+ }
+
+ if (enc->encrypt == krb5int_aes_encrypt && enc->keylength == 16)
+ cipher = EVP_aes_128_cbc();
+ else if (enc->encrypt == krb5int_aes_encrypt && enc->keylength == 32)
+ cipher = EVP_aes_256_cbc();
+ else if (enc->keylength == 24)
+ cipher = EVP_des_ede3_cbc();
+ else
+ goto done;
+
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KRB5KDF);
+ if (ctx == NULL)
+ goto done;
+
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_CIPHER, cipher) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents,
+ inkey->keyblock.length) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT,
+ in_constant->data, in_constant->length) != 1 ||
+ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data,
+ outrnd->length) != 1)
+ goto done;
+
+ ret = 0;
+done:
+ if (ret)
+ zap(outrnd->data, outrnd->length);
+ EVP_KDF_CTX_free(ctx);
+ return ret;
+}
+
+#else /* OSSL_KDFS */
+
+/*
+ * NIST SP800-108 KDF in counter mode (section 5.1).
+ * Parameters:
+ * - HMAC (with hash as the hash provider) is the PRF.
+ * - A block counter of four bytes is used.
+ * - Four bytes are used to encode the output length in the PRF input.
+ *
+ * There are no uses requiring more than a single PRF invocation.
+ */
+static krb5_error_code
+builtin_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *label,
+ const krb5_data *context)
+{
+ krb5_crypto_iov iov[5];
krb5_error_code ret;
- krb5_data block = empty_data();
+ krb5_data prf;
+ unsigned char ibuf[4], lbuf[4];
- blocksize = enc->block_size;
- keybytes = enc->keybytes;
-
- if (blocksize == 1)
- return KRB5_BAD_ENCTYPE;
- if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
+ if (hash == NULL || outrnd->length > hash->hashsize)
return KRB5_CRYPTO_INTERNAL;
/* Allocate encryption data buffer. */
- ret = alloc_data(&block, blocksize);
+ ret = alloc_data(&prf, hash->hashsize);
if (ret)
return ret;
- /* Initialize the input block. */
- if (in_constant->length == blocksize) {
- memcpy(block.data, in_constant->data, blocksize);
- } else {
- krb5int_nfold(in_constant->length * 8,
- (unsigned char *) in_constant->data,
- blocksize * 8, (unsigned char *) block.data);
- }
+ /* [i]2: four-byte big-endian binary string giving the block counter (1) */
+ iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[0].data = make_data(ibuf, sizeof(ibuf));
+ store_32_be(1, ibuf);
+ /* Label */
+ iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[1].data = *label;
+ /* 0x00: separator byte */
+ iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[2].data = make_data("", 1);
+ /* Context */
+ iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[3].data = *context;
+ /* [L]2: four-byte big-endian binary string giving the output length */
+ iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
+ iov[4].data = make_data(lbuf, sizeof(lbuf));
+ store_32_be(outrnd->length * 8, lbuf);
- /* Loop encrypting the blocks until enough key bytes are generated. */
- n = 0;
- while (n < keybytes) {
- ret = encrypt_block(enc, inkey, &block);
- if (ret)
- goto cleanup;
-
- if ((keybytes - n) <= blocksize) {
- memcpy(outrnd->data + n, block.data, (keybytes - n));
- break;
- }
-
- memcpy(outrnd->data + n, block.data, blocksize);
- n += blocksize;
- }
-
-cleanup:
- zapfree(block.data, blocksize);
+ ret = krb5int_hmac(hash, inkey, iov, 5, &prf);
+ if (!ret)
+ memcpy(outrnd->data, prf.data, outrnd->length);
+ zapfree(prf.data, prf.length);
return ret;
}
@@ -139,9 +284,9 @@ cleanup:
* - Four bytes are used to encode the output length in the PRF input.
*/
static krb5_error_code
-derive_random_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
- krb5_key inkey, krb5_data *outrnd,
- const krb5_data *in_constant)
+builtin_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
{
size_t blocksize, keybytes, n;
krb5_crypto_iov iov[6];
@@ -204,56 +349,94 @@ cleanup:
return ret;
}
-/*
- * NIST SP800-108 KDF in counter mode (section 5.1).
- * Parameters:
- * - HMAC (with hash as the hash provider) is the PRF.
- * - A block counter of four bytes is used.
- * - Four bytes are used to encode the output length in the PRF input.
- *
- * There are no uses requiring more than a single PRF invocation.
- */
+static krb5_error_code
+builtin_derive_random_rfc3961(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+ size_t blocksize, keybytes, n;
+ krb5_error_code ret;
+ krb5_data block = empty_data();
+
+ blocksize = enc->block_size;
+ keybytes = enc->keybytes;
+
+ if (blocksize == 1)
+ return KRB5_BAD_ENCTYPE;
+ if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
+ return KRB5_CRYPTO_INTERNAL;
+
+ /* Allocate encryption data buffer. */
+ ret = alloc_data(&block, blocksize);
+ if (ret)
+ return ret;
+
+ /* Initialize the input block. */
+ if (in_constant->length == blocksize) {
+ memcpy(block.data, in_constant->data, blocksize);
+ } else {
+ krb5int_nfold(in_constant->length * 8,
+ (unsigned char *) in_constant->data,
+ blocksize * 8, (unsigned char *) block.data);
+ }
+
+ /* Loop encrypting the blocks until enough key bytes are generated. */
+ n = 0;
+ while (n < keybytes) {
+ ret = encrypt_block(enc, inkey, &block);
+ if (ret)
+ goto cleanup;
+
+ if ((keybytes - n) <= blocksize) {
+ memcpy(outrnd->data + n, block.data, (keybytes - n));
+ break;
+ }
+
+ memcpy(outrnd->data + n, block.data, blocksize);
+ n += blocksize;
+ }
+
+cleanup:
+ zapfree(block.data, blocksize);
+ return ret;
+}
+#endif /* OSSL_KDFS */
+
krb5_error_code
k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
krb5_key inkey, krb5_data *outrnd,
const krb5_data *label, const krb5_data *context)
{
- krb5_crypto_iov iov[5];
- krb5_error_code ret;
- krb5_data prf;
- unsigned char ibuf[4], lbuf[4];
+#ifdef OSSL_KDFS
+ return openssl_kbdkf_counter_hmac(hash, inkey, outrnd, label, context);
+#else
+ return builtin_sp800_108_counter_hmac(hash, inkey, outrnd, label,
+ context);
+#endif
+}
- if (hash == NULL || outrnd->length > hash->hashsize)
- return KRB5_CRYPTO_INTERNAL;
+static krb5_error_code
+k5_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+#ifdef OSSL_KDFS
+ return openssl_kbkdf_feedback_cmac(enc, inkey, outrnd, in_constant);
+#else
+ return builtin_sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant);
+#endif
+}
- /* Allocate encryption data buffer. */
- ret = alloc_data(&prf, hash->hashsize);
- if (ret)
- return ret;
-
- /* [i]2: four-byte big-endian binary string giving the block counter (1) */
- iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[0].data = make_data(ibuf, sizeof(ibuf));
- store_32_be(1, ibuf);
- /* Label */
- iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[1].data = *label;
- /* 0x00: separator byte */
- iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[2].data = make_data("", 1);
- /* Context */
- iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[3].data = *context;
- /* [L]2: four-byte big-endian binary string giving the output length */
- iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
- iov[4].data = make_data(lbuf, sizeof(lbuf));
- store_32_be(outrnd->length * 8, lbuf);
-
- ret = krb5int_hmac(hash, inkey, iov, 5, &prf);
- if (!ret)
- memcpy(outrnd->data, prf.data, outrnd->length);
- zapfree(prf.data, prf.length);
- return ret;
+static krb5_error_code
+k5_derive_random_rfc3961(const struct krb5_enc_provider *enc,
+ krb5_key inkey, krb5_data *outrnd,
+ const krb5_data *in_constant)
+{
+#ifdef OSSL_KDFS
+ return openssl_krb5kdf(enc, inkey, outrnd, in_constant);
+#else
+ return builtin_derive_random_rfc3961(enc, inkey, outrnd, in_constant);
+#endif
}
krb5_error_code
@@ -266,10 +449,9 @@ krb5int_derive_random(const struct krb5_enc_provider *enc,
switch (alg) {
case DERIVE_RFC3961:
- return derive_random_rfc3961(enc, inkey, outrnd, in_constant);
+ return k5_derive_random_rfc3961(enc, inkey, outrnd, in_constant);
case DERIVE_SP800_108_CMAC:
- return derive_random_sp800_108_feedback_cmac(enc, inkey, outrnd,
- in_constant);
+ return k5_sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant);
case DERIVE_SP800_108_HMAC:
return k5_sp800_108_counter_hmac(hash, inkey, outrnd, in_constant,
&empty);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 52976895b..dd718c2be 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -38,6 +38,13 @@
#include <dirent.h>
#include <arpa/inet.h>
+#ifdef OSSL_KDFS
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#else
+#error "Refusing to build without OpenSSL KDFs!"
+#endif
+
static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context );
static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context );
@@ -2331,11 +2338,51 @@ pkinit_alg_values(krb5_context context,
}
} /* pkinit_alg_values() */
+#ifdef OSSL_KDFS
+static krb5_error_code
+openssl_sskdf(krb5_context context, size_t hash_bytes, krb5_data *key,
+ krb5_data *info, char *out, size_t out_len)
+{
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
+ EVP_KDF_CTX *ctx = NULL;
+ const EVP_MD *digest;
-/* pkinit_alg_agility_kdf() --
- * This function generates a key using the KDF described in
- * draft_ietf_krb_wg_pkinit_alg_agility-04.txt. The algorithm is
- * described as follows:
+ /* RFC 8636 defines a SHA384 variant, but we don't use it. */
+ if (hash_bytes == 20) {
+ digest = EVP_sha1();
+ } else if (hash_bytes == 32) {
+ digest = EVP_sha256();
+ } else if (hash_bytes == 64) {
+ digest = EVP_sha512();
+ } else {
+ krb5_set_error_message(context, ret, "Bad hash type for SSKDF");
+ goto done;
+ }
+
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_SS);
+ if (!ctx) {
+ oerr(context, ret, _("Failed to instantiate SSKDF"));
+ goto done;
+ }
+
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, key->data,
+ key->length) != 1 ||
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSKDF_INFO, info->data,
+ info->length) != 1 ||
+ EVP_KDF_derive(ctx, (unsigned char *)out, out_len) != 1)
+ goto done;
+
+ ret = 0;
+done:
+ EVP_KDF_CTX_free(ctx);
+ return ret;
+}
+#else
+/*
+ * Generate a key using the KDF described in RFC 8636, also known as SSKDF
+ * (single-step kdf). Our caller precomputes `reps`, but otherwise the
+ * algorithm is as follows:
*
* 1. reps = keydatalen (K) / hash length (H)
*
@@ -2349,95 +2396,16 @@ pkinit_alg_values(krb5_context context,
*
* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes.
*/
-krb5_error_code
-pkinit_alg_agility_kdf(krb5_context context,
- krb5_data *secret,
- krb5_data *alg_oid,
- krb5_const_principal party_u_info,
- krb5_const_principal party_v_info,
- krb5_enctype enctype,
- krb5_data *as_req,
- krb5_data *pk_as_rep,
- krb5_keyblock *key_block)
+static krb5_error_code
+builtin_sskdf(krb5_context context, unsigned int reps, size_t hash_len,
+ const EVP_MD *(*EVP_func)(void), krb5_data *secret,
+ krb5_data *other_info, char *out, size_t out_len)
{
krb5_error_code retval = 0;
- unsigned int reps = 0;
- uint32_t counter = 1; /* Does this type work on Windows? */
+ uint32_t counter = 1;
size_t offset = 0;
- size_t hash_len = 0;
- size_t rand_len = 0;
- size_t key_len = 0;
- krb5_data random_data;
- krb5_sp80056a_other_info other_info_fields;
- krb5_pkinit_supp_pub_info supp_pub_info_fields;
- krb5_data *other_info = NULL;
- krb5_data *supp_pub_info = NULL;
- krb5_algorithm_identifier alg_id;
EVP_MD_CTX *ctx = NULL;
- const EVP_MD *(*EVP_func)(void);
-
- /* initialize random_data here to make clean-up safe */
- random_data.length = 0;
- random_data.data = NULL;
-
- /* allocate and initialize the key block */
- key_block->magic = 0;
- key_block->enctype = enctype;
- if (0 != (retval = krb5_c_keylengths(context, enctype, &rand_len,
- &key_len)))
- goto cleanup;
-
- random_data.length = rand_len;
- key_block->length = key_len;
-
- if (NULL == (key_block->contents = malloc(key_block->length))) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- memset (key_block->contents, 0, key_block->length);
-
- /* If this is anonymous pkinit, use the anonymous principle for party_u_info */
- if (party_u_info && krb5_principal_compare_any_realm(context, party_u_info,
- krb5_anonymous_principal()))
- party_u_info = (krb5_principal)krb5_anonymous_principal();
-
- if (0 != (retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func)))
- goto cleanup;
-
- /* 1. reps = keydatalen (K) / hash length (H) */
- reps = key_block->length/hash_len;
-
- /* ... and round up, if necessary */
- if (key_block->length > (reps * hash_len))
- reps++;
-
- /* Allocate enough space in the random data buffer to hash directly into
- * it, even if the last hash will make it bigger than the key length. */
- if (NULL == (random_data.data = malloc(reps * hash_len))) {
- retval = ENOMEM;
- goto cleanup;
- }
-
- /* Encode the ASN.1 octet string for "SuppPubInfo" */
- supp_pub_info_fields.enctype = enctype;
- supp_pub_info_fields.as_req = *as_req;
- supp_pub_info_fields.pk_as_rep = *pk_as_rep;
- if (0 != ((retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
- &supp_pub_info))))
- goto cleanup;
-
- /* Now encode the ASN.1 octet string for "OtherInfo" */
- memset(&alg_id, 0, sizeof alg_id);
- alg_id.algorithm = *alg_oid; /*alias*/
-
- other_info_fields.algorithm_identifier = alg_id;
- other_info_fields.party_u_info = (krb5_principal) party_u_info;
- other_info_fields.party_v_info = (krb5_principal) party_v_info;
- other_info_fields.supp_pub_info = *supp_pub_info;
- if (0 != (retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info)))
- goto cleanup;
/* 2. Initialize a 32-bit, big-endian bit string counter as 1.
* 3. For i = 1 to reps by 1, do the following:
@@ -2471,8 +2439,9 @@ pkinit_alg_agility_kdf(krb5_context context,
goto cleanup;
}
- /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes. */
- if (!EVP_DigestFinal(ctx, (uint8_t *)random_data.data + offset, &s)) {
+ /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K
+ * bytes. */
+ if (!EVP_DigestFinal(ctx, (unsigned char *)out + offset, &s)) {
krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
"Call to OpenSSL EVP_DigestUpdate() returned an error.");
retval = KRB5_CRYPTO_INTERNAL;
@@ -2484,26 +2453,110 @@ pkinit_alg_agility_kdf(krb5_context context,
EVP_MD_CTX_free(ctx);
ctx = NULL;
}
-
- retval = krb5_c_random_to_key(context, enctype, &random_data,
- key_block);
-
cleanup:
EVP_MD_CTX_free(ctx);
+ return retval;
+} /* builtin_sskdf() */
+#endif /* OSSL_KDFS */
- /* If this has been an error, free the allocated key_block, if any */
- if (retval) {
- krb5_free_keyblock_contents(context, key_block);
+/* id-pkinit-kdf family, as specified by RFC 8636. */
+krb5_error_code
+pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
+ krb5_data *alg_oid, krb5_const_principal party_u_info,
+ krb5_const_principal party_v_info,
+ krb5_enctype enctype, krb5_data *as_req,
+ krb5_data *pk_as_rep, krb5_keyblock *key_block)
+{
+ krb5_error_code retval;
+ size_t hash_len = 0, rand_len = 0, key_len = 0;
+ const EVP_MD *(*EVP_func)(void);
+ krb5_sp80056a_other_info other_info_fields;
+ krb5_pkinit_supp_pub_info supp_pub_info_fields;
+ krb5_data *other_info = NULL, *supp_pub_info = NULL;
+ krb5_data random_data = empty_data();
+ krb5_algorithm_identifier alg_id;
+ unsigned int reps;
+
+ /* Allocate and initialize the key block. */
+ key_block->magic = 0;
+ key_block->enctype = enctype;
+
+ /* Use separate variables to avoid alignment restriction problems. */
+ retval = krb5_c_keylengths(context, enctype, &rand_len, &key_len);
+ if (retval)
+ goto cleanup;
+ random_data.length = rand_len;
+ key_block->length = key_len;
+
+ key_block->contents = k5calloc(key_block->length, 1, &retval);
+ if (key_block->contents == NULL)
+ goto cleanup;
+
+ /* If this is anonymous pkinit, use the anonymous principle for
+ * party_u_info. */
+ if (party_u_info &&
+ krb5_principal_compare_any_realm(context, party_u_info,
+ krb5_anonymous_principal())) {
+ party_u_info = (krb5_principal)krb5_anonymous_principal();
}
- /* free other allocated resources, either way */
- if (random_data.data)
- free(random_data.data);
+ retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func);
+ if (retval)
+ goto cleanup;
+
+ /* 1. reps = keydatalen (K) / hash length (H) */
+ reps = key_block->length / hash_len;
+
+ /* ... and round up, if necessary. */
+ if (key_block->length > (reps * hash_len))
+ reps++;
+
+ /* Allocate enough space in the random data buffer to hash directly into
+ * it, even if the last hash will make it bigger than the key length. */
+ random_data.data = k5alloc(reps * hash_len, &retval);
+ if (random_data.data == NULL)
+ goto cleanup;
+
+ /* Encode the ASN.1 octet string for "SuppPubInfo". */
+ supp_pub_info_fields.enctype = enctype;
+ supp_pub_info_fields.as_req = *as_req;
+ supp_pub_info_fields.pk_as_rep = *pk_as_rep;
+ retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
+ &supp_pub_info);
+ if (retval)
+ goto cleanup;
+
+ /* Now encode the ASN.1 octet string for "OtherInfo". */
+ memset(&alg_id, 0, sizeof(alg_id));
+ alg_id.algorithm = *alg_oid;
+ other_info_fields.algorithm_identifier = alg_id;
+ other_info_fields.party_u_info = (krb5_principal)party_u_info;
+ other_info_fields.party_v_info = (krb5_principal)party_v_info;
+ other_info_fields.supp_pub_info = *supp_pub_info;
+ retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info);
+ if (retval)
+ goto cleanup;
+
+#ifdef OSSL_KDFS
+ retval = openssl_sskdf(context, hash_len, secret, other_info,
+ random_data.data, key_block->length);
+#else
+ retval = builtin_sskdf(context, reps, hash_len, EVP_func, secret,
+ other_info, random_data.data, key_block->length);
+#endif
+ if (retval)
+ goto cleanup;
+
+ retval = krb5_c_random_to_key(context, enctype, &random_data, key_block);
+cleanup:
+ if (retval)
+ krb5_free_keyblock_contents(context, key_block);
+
+ zapfree(random_data.data, random_data.length);
krb5_free_data(context, other_info);
krb5_free_data(context, supp_pub_info);
-
return retval;
-} /*pkinit_alg_agility_kdf() */
+}
/* Call DH_compute_key() and ensure that we left-pad short results instead of
* leaving junk bytes at the end of the buffer. */

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save