Compare commits

..

22 commits

Author SHA1 Message Date
Julien Rische
ee9e3fc1e1 Try harder to avoid password change replay errors
change_set_password() was changed 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.

Resolves: rhbz#2076965

Signed-off-by: Julien Rische <jrische@redhat.com>
2022-04-20 17:17:09 +02:00
Alexander Bokovoy
114b35c436 Fix libkrad client cleanup code
Resolves: rhbz#2072059

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2022-04-05 22:14:44 +03:00
Alexander Bokovoy
e66c7a3a81 Allow use of larger RADIUS attributes in krad library
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)

From upstream, needed in preparation for OAuth2 support for FreeIPA and
SSSD.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2022-04-05 16:55:31 +03:00
Julien Rische
2deca4e8cd Use SHA-256 instead of SHA-1 for PKINIT CMS digest
CMS digest and signature algorithm for the anonymous PKINIT is changed
from SHA-1 to SHA-256. SHA-1 hasn't been considered secure anymore for
this kind of purposes for some years already.

Resolves: rhbz#2067121

Signed-off-by: Julien Rische <jrische@redhat.com>
2022-03-23 13:16:13 +01:00
Robbie Harwood
d693d44347 Fix KDC null deref on TGS inner body null server (CVE-2021-37750) 2021-08-19 12:32:16 -04:00
Robbie Harwood
3cd2cfc1c6 Add sources 2021-08-19 12:32:16 -04:00
Robbie Harwood
f4fc3f0f46 New upstream version (1.19.2) 2021-08-19 12:32:16 -04:00
Robbie Harwood
75a24fdad1 Fix defcred leak in krb5 gss_inquire_cred() 2021-08-19 12:32:16 -04:00
Robbie Harwood
d4c49281cc Fix KDC null deref on bad encrypted challenge (CVE-2021-36222) 2021-07-12 13:12:39 -04:00
Robbie Harwood
e2cba14cf1 Fix use-after-free during krad remote_shutdown() 2021-07-12 13:12:39 -04:00
Robbie Harwood
9450abbfbc MEMORY locking fix and static analysis pullup 2021-07-12 13:12:39 -04:00
Robbie Harwood
1806554414 Add the backward-compatible parts of openssl3 support 2021-07-12 13:12:39 -04:00
Robbie Harwood
09eff6f6df Fix three canonicalization cases for fallback 2021-07-12 13:12:39 -04:00
Robbie Harwood
5bbe654d61 Fix doc build for Sphinx 4.0 2021-07-12 13:12:39 -04:00
Robbie Harwood
ee6f543041 Add all the sssd-kcm workarounds
(cherry picked from commit 72e80d67ef)
2021-05-20 17:26:40 -04:00
Robbie Harwood
e76f184909 Fix context for previous backport
(cherry picked from commit c4150c67d1)
2021-05-20 14:04:29 -04:00
Robbie Harwood
a987c5f3a2 Add KCM_OP_GET_CRED_LIST and KCM_OP_RETRIEVE support
(cherry picked from commit 904d264a41)
2021-05-20 14:04:29 -04:00
Robbie Harwood
b407176c1f Remove broken gating file
Currently the gating file prevents building:

    rharwood@eesha:~/krb5.fedora/rawhide$ fedpkg build
    Could not execute build: Found a gating.yaml file in your repo with additional Greenwave policies, but it is not valid.
    Please fix the file or skip this check using the option --skip-remote-rules-validation.
    Error response from Greenwave: YAML Parser Error: mapping values are not allowed here
      in "<unicode string>", line 2, column 18:
           product_versions:
                                ^
    rharwood@eesha:~/krb5.fedora/rawhide$

Patches to add it back will be considered if and only if they don't
break the build.

(cherry picked from commit 69e05d5e39)
2021-05-20 14:04:15 -04:00
Robbie Harwood
be7528aa8e Suppress static analyzer warning in FIPS override
(cherry picked from commit e9fb111a11)
2021-05-20 14:04:10 -04:00
Robbie Harwood
2f63f28a76 Add rpminspect configuration
(cherry picked from commit 1c2362203e)
2021-05-20 14:04:06 -04:00
Miroslav Vadkerti
3892b7fc8e Onboard krb5 to downstream gating
Because krb5 is auto-synced via DistroBaker, we need to add
downstream gating configuration in Fedora.

Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
2021-03-30 14:38:16 -04:00
Robbie Harwood
c22d77ba16 Fix the mess the mass rebuild made of Release 2021-03-30 09:07:45 -04:00
93 changed files with 7953 additions and 25256 deletions

View file

@ -1 +0,0 @@
1

101
.gitignore vendored
View file

@ -1,50 +1,49 @@
/results_krb5
/krb5-1.3.4.tar.gz
/krb5-1.3.5.tar.gz
/krb5-1.3.5.tar.gz.asc
/krb5-1.3.6.tar.gz
/krb5-1.3.6.tar.gz.asc
/krb5-1.4.tar.gz
/krb5-1.4.tar.gz.asc
/krb5-1.4.1.tar.gz
/krb5-1.4.1.tar.gz.asc
/krb5-1.4.2.tar.gz
/krb5-1.4.2.tar.gz.asc
/krb5-1.4.3.tar.gz
/krb5-1.4.3.tar.gz.asc
/krb5-1.5.tar.gz
/krb5-1.5.tar.gz.asc
/krb5-1.6.tar.gz
/krb5-1.6.tar.gz.asc
/krb5-1.6-pdf.tar.gz
/krb5-1.6.1.tar.gz
/krb5-1.6.1.tar.gz.asc
/krb5-1.6.1-pdf.tar.gz
/krb5-1.6.2.tar.gz
/krb5-1.6.2.tar.gz.asc
/krb5-1.6.2-pdf.tar.gz
/krb5-1.6.3.tar.gz
/krb5-1.6.3.tar.gz.asc
/krb5-1.6.3-pdf.tar.gz
/krb5-1.7.tar.gz
/krb5-1.7.tar.gz.asc
/krb5-1.7-pdf.tar.gz
/krb5-1.7.1.tar.gz
/krb5-1.7.1.tar.gz.asc
/krb5-1.7.1-pdf.tar.gz
/krb5-1.8.tar.gz
/krb5-1.8.tar.gz.asc
/krb5-appl-1.0.tar.gz
/krb5-appl-1.0.tar.gz.asc
/krb5-1.8-pdf.tar.gz
/krb5-1.8.1.tar.gz
/krb5-1.8.1.tar.gz.asc
/krb5-1.8.1-pdf.tar.gz
/krb5-1.8.2.tar.gz.asc
/krb5-1.8.2-pdf.tar.gz
/krb5-1.8.3.tar.gz
/krb5-1.8.3.tar.gz.asc
/krb5-1.8.3-pdf.tar.gz
krb5-1.3.4.tar.gz
krb5-1.3.5.tar.gz
krb5-1.3.5.tar.gz.asc
krb5-1.3.6.tar.gz
krb5-1.3.6.tar.gz.asc
krb5-1.4.tar.gz
krb5-1.4.tar.gz.asc
krb5-1.4.1.tar.gz
krb5-1.4.1.tar.gz.asc
krb5-1.4.2.tar.gz
krb5-1.4.2.tar.gz.asc
krb5-1.4.3.tar.gz
krb5-1.4.3.tar.gz.asc
krb5-1.5.tar.gz
krb5-1.5.tar.gz.asc
krb5-1.6.tar.gz
krb5-1.6.tar.gz.asc
krb5-1.6-pdf.tar.gz
krb5-1.6.1.tar.gz
krb5-1.6.1.tar.gz.asc
krb5-1.6.1-pdf.tar.gz
krb5-1.6.2.tar.gz
krb5-1.6.2.tar.gz.asc
krb5-1.6.2-pdf.tar.gz
krb5-1.6.3.tar.gz
krb5-1.6.3.tar.gz.asc
krb5-1.6.3-pdf.tar.gz
krb5-1.7.tar.gz
krb5-1.7.tar.gz.asc
krb5-1.7-pdf.tar.gz
krb5-1.7.1.tar.gz
krb5-1.7.1.tar.gz.asc
krb5-1.7.1-pdf.tar.gz
krb5-1.8.tar.gz
krb5-1.8.tar.gz.asc
krb5-appl-1.0.tar.gz
krb5-appl-1.0.tar.gz.asc
krb5-1.8-pdf.tar.gz
krb5-1.8.1.tar.gz
krb5-1.8.1.tar.gz.asc
krb5-1.8.1-pdf.tar.gz
krb5-1.8.2.tar.gz.asc
krb5-1.8.2-pdf.tar.gz
krb5-1.8.3.tar.gz
krb5-1.8.3.tar.gz.asc
krb5-1.8.3-pdf.tar.gz
/krb5-1.9-beta2.tar.gz
/krb5-1.9-beta2.tar.gz.asc
/krb5-1.9-beta2-pdf.tar.bz2
@ -200,11 +199,3 @@
/krb5-1.19.1.tar.gz.asc
/krb5-1.19.2.tar.gz
/krb5-1.19.2.tar.gz.asc
/krb5-1.20.1.tar.gz
/krb5-1.20.1.tar.gz.asc
/krb5-1.21.tar.gz
/krb5-1.21.tar.gz.asc
/krb5-1.21.2.tar.gz
/krb5-1.21.2.tar.gz.asc
/krb5-1.21.3.tar.gz
/krb5-1.21.3.tar.gz.asc

View file

@ -1,310 +0,0 @@
From 6f7fd964539dfe4a885068f43a91db9738661870 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Tue, 9 Jul 2024 11:15:33 +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.45.1

View file

@ -1,82 +0,0 @@
From 707fa7bd2be6327343dc8fc5c20dc77645524518 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.45.1

View file

@ -1,41 +0,0 @@
From 1da88bea558348be2974470774aa688f8be634c0 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.45.1

View file

@ -1,120 +0,0 @@
From 775ed8588cc21385fb16a4cec4a861f0d578ce04 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.45.1

View file

@ -1,31 +0,0 @@
From 4fd20741afcf76085ea62eb015cd589bb9392a7b 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.45.1

View file

@ -1,165 +0,0 @@
From 16f90c007036789d8d9343e8a0cbabfd21853b5a 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.45.1

View file

@ -1,280 +0,0 @@
From 23b58199db429603802e338db530677b61561335 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 c5a625db8f..2d9b64dc85 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -8329,6 +8329,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 8413e70ccd..f68eb0569d 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.45.1

View file

@ -1,47 +0,0 @@
From 31b9debcf2cbd558f8f315fefb69fc8206b115b4 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 cb9c79626c..17dd18e37d 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.45.1

View file

@ -1,218 +0,0 @@
From c24c9faf859ddc04910a6bc591d8ddb2ada93e80 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)
(cherry picked from commit 509d8db922e9ad6f108883838473b6178f89874a)
---
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 17dd18e37d..8cdc40bfb4 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
@@ -2912,11 +2920,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;
@@ -3212,19 +3220,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.45.1

View file

@ -1,64 +0,0 @@
From e92365b510a2407eaceaec90836f5c713403d75f Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 19 Jul 2023 13:43:17 +0200
Subject: [PATCH] Replace ssl.wrap_socket() for tests
The ssl.wrap_socket() function was deprecated in Python 3.7 and is
removed in Python 3.12. The ssl.SSLContext.wrap_socket() method
replaces it.
Bump the required Python version for tests to 3.4 for
ssl.create_default_context().
[ghudson@mit.edu: changed minimum Python version]
(cherry picked from commit 0ceab6c363e65fb21d3312a663f2b9b569ecc415)
---
src/configure.ac | 9 ++++-----
src/util/wsgiref-kdcproxy.py | 4 +++-
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/configure.ac b/src/configure.ac
index 2561e917a2..487f393146 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1157,10 +1157,9 @@ AC_SUBST(PKINIT)
# for lib/apputils
AC_REPLACE_FUNCS(daemon)
-# For Python tests. Python version 3.2.4 is required as prior
-# versions do not accept string input to subprocess.Popen.communicate
-# when universal_newlines is set.
-PYTHON_MINVERSION=3.2.4
+# For Python tests. Python version 3.4 is required for
+# ssl.create_default_context().
+PYTHON_MINVERSION=3.4
AC_SUBST(PYTHON_MINVERSION)
AC_CHECK_PROG(PYTHON,python3,python3)
if test x"$PYTHON" = x; then
@@ -1168,7 +1167,7 @@ if test x"$PYTHON" = x; then
fi
HAVE_PYTHON=no
if test x"$PYTHON" != x; then
- wantver="(sys.hexversion >= 0x30204F0)"
+ wantver="(sys.hexversion >= 0x30400F0)"
if "$PYTHON" -c "import sys; sys.exit(not $wantver and 1 or 0)"; then
HAVE_PYTHON=yes
fi
diff --git a/src/util/wsgiref-kdcproxy.py b/src/util/wsgiref-kdcproxy.py
index 58759696b6..d1d10d733c 100755
--- a/src/util/wsgiref-kdcproxy.py
+++ b/src/util/wsgiref-kdcproxy.py
@@ -14,6 +14,8 @@ else:
pem = '*'
server = make_server('localhost', port, kdcproxy.Application())
-server.socket = ssl.wrap_socket(server.socket, certfile=pem, server_side=True)
+sslctx = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
+sslctx.load_cert_chain(certfile=pem)
+server.socket = sslctx.wrap_socket(server.socket, server_side=True)
os.write(sys.stdout.fileno(), b'proxy server ready\n')
server.serve_forever()
--
2.45.1

File diff suppressed because it is too large Load diff

View file

@ -1,206 +0,0 @@
From ee66c1feedb57ce06ce51aaa823f9a61f564c58e 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
In gss_krb5int_make_seal_token_v3(), one of the bounds checks (which
could probably never be triggered) leaks plain.data. Fix this leak
and use current practices for cleanup throughout the function.
In xmt_rmtcallres() (unused within the tree and likely elsewhere),
store port_ptr into crp->port_ptr as soon as it is allocated;
otherwise it could leak if the subsequent xdr_u_int32() operation
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(-)
diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c
index 1fcbdfbb87..d3210c1107 100644
--- a/src/lib/gssapi/krb5/k5sealv3.c
+++ b/src/lib/gssapi/krb5/k5sealv3.c
@@ -65,7 +65,7 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
int conf_req_flag, int toktype)
{
size_t bufsize = 16;
- unsigned char *outbuf = 0;
+ unsigned char *outbuf = NULL;
krb5_error_code err;
int key_usage;
unsigned char acceptor_flag;
@@ -75,9 +75,13 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
#endif
size_t ec;
unsigned short tok_id;
- krb5_checksum sum;
+ krb5_checksum sum = { 0 };
krb5_key key;
krb5_cksumtype cksumtype;
+ krb5_data plain = empty_data();
+
+ token->value = NULL;
+ token->length = 0;
acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
key_usage = (toktype == KG_TOK_WRAP_MSG
@@ -107,14 +111,15 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
#endif
if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
- krb5_data plain;
krb5_enc_data cipher;
size_t ec_max;
size_t encrypt_size;
/* 300: Adds some slop. */
- if (SIZE_MAX - 300 < message->length)
- return ENOMEM;
+ if (SIZE_MAX - 300 < message->length) {
+ err = ENOMEM;
+ goto cleanup;
+ }
ec_max = SIZE_MAX - message->length - 300;
if (ec_max > 0xffff)
ec_max = 0xffff;
@@ -126,20 +131,20 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
#endif
err = alloc_data(&plain, message->length + 16 + ec);
if (err)
- return err;
+ goto cleanup;
/* Get size of ciphertext. */
encrypt_size = krb5_encrypt_size(plain.length, key->keyblock.enctype);
if (encrypt_size > SIZE_MAX / 2) {
err = ENOMEM;
- goto error;
+ goto cleanup;
}
bufsize = 16 + encrypt_size;
/* Allocate space for header plus encrypted data. */
outbuf = gssalloc_malloc(bufsize);
if (outbuf == NULL) {
- free(plain.data);
- return ENOMEM;
+ err = ENOMEM;
+ goto cleanup;
}
/* TOK_ID */
@@ -164,11 +169,8 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
cipher.ciphertext.length = bufsize - 16;
cipher.enctype = key->keyblock.enctype;
err = krb5_k_encrypt(context, key, key_usage, 0, &plain, &cipher);
- zap(plain.data, plain.length);
- free(plain.data);
- plain.data = 0;
if (err)
- goto error;
+ goto cleanup;
/* Now that we know we're returning a valid token.... */
ctx->seq_send++;
@@ -181,7 +183,6 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
/* If the rotate fails, don't worry about it. */
#endif
} else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
- krb5_data plain;
size_t cksumsize;
/* Here, message is the application-supplied data; message2 is
@@ -193,21 +194,19 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
wrap_with_checksum:
err = alloc_data(&plain, message->length + 16);
if (err)
- return err;
+ goto cleanup;
err = krb5_c_checksum_length(context, cksumtype, &cksumsize);
if (err)
- goto error;
+ goto cleanup;
assert(cksumsize <= 0xffff);
bufsize = 16 + message2->length + cksumsize;
outbuf = gssalloc_malloc(bufsize);
if (outbuf == NULL) {
- free(plain.data);
- plain.data = 0;
err = ENOMEM;
- goto error;
+ goto cleanup;
}
/* TOK_ID */
@@ -239,23 +238,15 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
if (message2->length)
memcpy(outbuf + 16, message2->value, message2->length);
- sum.contents = outbuf + 16 + message2->length;
- sum.length = cksumsize;
-
err = krb5_k_make_checksum(context, cksumtype, key,
key_usage, &plain, &sum);
- zap(plain.data, plain.length);
- free(plain.data);
- plain.data = 0;
if (err) {
zap(outbuf,bufsize);
- goto error;
+ goto cleanup;
}
if (sum.length != cksumsize)
abort();
memcpy(outbuf + 16 + message2->length, sum.contents, cksumsize);
- krb5_free_checksum_contents(context, &sum);
- sum.contents = 0;
/* Now that we know we're actually generating the token... */
ctx->seq_send++;
@@ -285,12 +276,13 @@ gss_krb5int_make_seal_token_v3 (krb5_context context,
token->value = outbuf;
token->length = bufsize;
- return 0;
+ outbuf = NULL;
+ err = 0;
-error:
+cleanup:
+ krb5_free_checksum_contents(context, &sum);
+ zapfree(plain.data, plain.length);
gssalloc_free(outbuf);
- token->value = NULL;
- token->length = 0;
return err;
}
diff --git a/src/lib/rpc/pmap_rmt.c b/src/lib/rpc/pmap_rmt.c
index 434e4eea65..f55ca46c60 100644
--- a/src/lib/rpc/pmap_rmt.c
+++ b/src/lib/rpc/pmap_rmt.c
@@ -161,12 +161,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)) {
- crp->port_ptr = (uint32_t *)(void *)port_ptr;
+ if (!xdr_reference(xdrs, &port_ptr, sizeof (uint32_t),
+ (xdrproc_t)xdr_u_int32))
+ return (FALSE);
+ crp->port_ptr = (uint32_t *)(void *)port_ptr;
+ if (xdr_u_int32(xdrs, &crp->resultslen))
return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
- }
return (FALSE);
}
--
2.45.1

File diff suppressed because it is too large Load diff

View file

@ -1,71 +0,0 @@
From 05bb6d9c729a3c6a4ba35270368bc0f6e1875ad0 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Mon, 8 Jan 2024 16:52:27 +0100
Subject: [PATCH] Remove klist's defname global variable
Addition of a "cleanup" section in kinit's show_ccache() function as
part of commit 6c5471176f5266564fbc8a7e02f03b4b042202f8 introduced a
double-free bug, because defname is a global variable. After the
first call, successive calls may take place with a dangling pointer in
defname, which will be freed if krb5_cc_get_principal() fails.
Convert "defname" to a local variable initialized at the beginning of
show_ccache().
[ghudson@mit.edu: edited commit message]
(cherry picked from commit 5b00197227231943bd2305328c8260dd0b0dbcf0)
---
src/clients/klist/klist.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c
index b5ae96a843..b5808e5c93 100644
--- a/src/clients/klist/klist.c
+++ b/src/clients/klist/klist.c
@@ -53,7 +53,6 @@ int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0;
int show_etype = 0, show_addresses = 0, no_resolve = 0, print_version = 0;
int show_adtype = 0, show_all = 0, list_all = 0, use_client_keytab = 0;
int show_config = 0;
-char *defname;
char *progname;
krb5_timestamp now;
unsigned int timestamp_width;
@@ -62,7 +61,7 @@ krb5_context context;
static krb5_boolean is_local_tgt(krb5_principal princ, krb5_data *realm);
static char *etype_string(krb5_enctype );
-static void show_credential(krb5_creds *);
+static void show_credential(krb5_creds *, const char *);
static void list_all_ccaches(void);
static int list_ccache(krb5_ccache);
@@ -473,6 +472,7 @@ show_ccache(krb5_ccache cache)
krb5_creds creds;
krb5_principal princ = NULL;
krb5_error_code ret;
+ char *defname = NULL;
int status = 1;
ret = krb5_cc_get_principal(context, cache, &princ);
@@ -503,7 +503,7 @@ show_ccache(krb5_ccache cache)
}
while ((ret = krb5_cc_next_cred(context, cache, &cur, &creds)) == 0) {
if (show_config || !krb5_is_config_principal(context, creds.server))
- show_credential(&creds);
+ show_credential(&creds, defname);
krb5_free_cred_contents(context, &creds);
}
if (ret == KRB5_CC_END) {
@@ -676,7 +676,7 @@ print_config_data(int col, krb5_data *data)
}
static void
-show_credential(krb5_creds *cred)
+show_credential(krb5_creds *cred, const char *defname)
{
krb5_error_code ret;
krb5_ticket *tkt = NULL;
--
2.45.1

View file

@ -1,34 +0,0 @@
From d7bcca2a215de880f4419afc450a96a747d48560 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
In sendto_kdc.c:service_fds(), if a message handler indicates that a
message should be discarded, kill the connection so we don't continue
waiting on it for more data.
ticket: 7899
(cherry picked from commit ca80f64c786341d5871ae1de18142e62af64f7b9)
---
src/lib/krb5/os/sendto_kdc.c | 5 ++++-
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
--- 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,
if (msg_handler != NULL) {
krb5_data reply = make_data(state->in.buf, state->in.pos);
- stop = (msg_handler(context, &reply, msg_handler_data) != 0);
+ if (!msg_handler(context, &reply, msg_handler_data)) {
+ kill_conn(context, state, selstate);
+ stop = 0;
+ }
}
if (stop) {
--
2.46.0

View file

@ -1,226 +0,0 @@
From a07b3ae29fd972c40e30b95f6bcc8fb3ed4d9991 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
Add a parameter to limit the total amount of time taken for a KDC or
password change request.
ticket: 9106 (new)
(cherry picked from commit 802318cda963456b3ed7856c836e89da891483be)
---
doc/admin/conf_files/krb5_conf.rst | 9 ++++++
src/include/k5-int.h | 2 ++
src/lib/krb5/krb/init_ctx.c | 14 +++++++-
src/lib/krb5/os/sendto_kdc.c | 51 ++++++++++++++++++++----------
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
--- 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:
(:ref:`duration` string.) Sets the default renewable lifetime
for initial ticket requests. The default value is 0.
+**request_timeout**
+ (:ref:`duration` string.) Sets the maximum total time for KDC or
+ password change requests. This timeout does not affect the
+ intervals between requests, so setting a low timeout may result in
+ fewer requests being attempted and/or some servers not being
+ contacted. A value of 0 indicates no specific maximum, in which
+ case requests will time out if no server responds after several
+ tries. The default value is 0. (New in release 1.22.)
+
**spake_preauth_groups**
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
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -296,6 +296,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"
+#define KRB5_CONF_REQUEST_TIMEOUT "request_timeout"
#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 {
kdb5_dal_handle *dal_handle;
/* allowable clock skew */
krb5_deltat clockskew;
+ krb5_deltat req_timeout;
krb5_flags kdc_default_options;
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
--- 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;
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,
get_integer(ctx, KRB5_CONF_CLOCKSKEW, DEFAULT_CLOCKSKEW, &tmp);
ctx->clockskew = tmp;
+ retval = profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS,
+ KRB5_CONF_REQUEST_TIMEOUT, NULL, NULL,
+ &timeout_str);
+ if (retval)
+ goto cleanup;
+ if (timeout_str != NULL) {
+ retval = krb5_string_to_deltat(timeout_str, &ctx->req_timeout);
+ if (retval)
+ goto cleanup;
+ }
+
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,
cleanup:
profile_release_string(plugin_dir);
+ profile_release_string(timeout_str);
krb5_free_context(ctx);
return retval;
}
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index 262edf09b4..98247a1089 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)
static krb5_boolean
service_fds(krb5_context context, struct select_state *selstate,
- time_ms interval, struct conn_state *conns,
+ time_ms interval, time_ms timeout, struct conn_state *conns,
struct select_state *seltemp, const krb5_data *realm,
int (*msg_handler)(krb5_context, const krb5_data *, void *),
void *msg_handler_data, struct conn_state **winner_out)
{
int e, selret = 0;
- time_ms endtime;
+ time_ms curtime, interval_end, endtime;
struct conn_state *state;
*winner_out = NULL;
- e = get_curtime_ms(&endtime);
+ e = get_curtime_ms(&curtime);
if (e)
return TRUE;
- endtime += interval;
+ interval_end = curtime + interval;
e = 0;
while (selstate->nfds > 0) {
- e = cm_select_or_poll(selstate, get_endtime(endtime, conns),
- seltemp, &selret);
+ endtime = get_endtime(interval_end, conns);
+ /* Don't wait longer than the whole request should last. */
+ if (timeout && endtime > timeout)
+ endtime = timeout;
+ e = cm_select_or_poll(selstate, endtime, seltemp, &selret);
if (e == EINTR)
continue;
if (e != 0)
break;
- if (selret == 0)
- /* Timeout, return to caller. */
+ if (selret == 0) {
+ /* We timed out. Stop if we hit the overall request timeout. */
+ if (timeout && (get_curtime_ms(&curtime) || curtime >= timeout))
+ return TRUE;
+ /* Otherwise return to the caller to send the next request. */
return FALSE;
+ }
/* 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,
void *msg_handler_data)
{
int pass;
- time_ms delay;
+ time_ms delay, timeout = 0;
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,
*reply = empty_data();
+ if (context->req_timeout) {
+ retval = get_curtime_ms(&timeout);
+ if (retval)
+ return retval;
+ timeout += 1000 * context->req_timeout;
+ }
+
/* 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,
if (maybe_send(context, state, message, sel_state, realm,
callback_info))
continue;
- done = service_fds(context, sel_state, 1000, conns, seltemp,
- realm, msg_handler, msg_handler_data, &winner);
+ done = service_fds(context, sel_state, 1000, timeout, conns,
+ seltemp, realm, msg_handler, msg_handler_data,
+ &winner);
}
}
@@ -1545,13 +1560,13 @@ k5_sendto(krb5_context context, const krb5_data *message,
if (maybe_send(context, state, message, sel_state, realm,
callback_info))
continue;
- done = service_fds(context, sel_state, 1000, conns, seltemp,
+ done = service_fds(context, sel_state, 1000, timeout, conns, seltemp,
realm, msg_handler, msg_handler_data, &winner);
}
/* Wait for two seconds at the end of the first pass. */
if (!done) {
- done = service_fds(context, sel_state, 2000, conns, seltemp,
+ done = service_fds(context, sel_state, 2000, timeout, conns, seltemp,
realm, msg_handler, msg_handler_data, &winner);
}
@@ -1562,15 +1577,17 @@ k5_sendto(krb5_context context, const krb5_data *message,
if (maybe_send(context, state, message, sel_state, realm,
callback_info))
continue;
- done = service_fds(context, sel_state, 1000, conns, seltemp,
- realm, msg_handler, msg_handler_data, &winner);
+ done = service_fds(context, sel_state, 1000, timeout, conns,
+ seltemp, realm, msg_handler, msg_handler_data,
+ &winner);
if (sel_state->nfds == 0)
break;
}
/* Wait for the delay backoff at the end of this pass. */
if (!done) {
- done = service_fds(context, sel_state, delay, conns, seltemp,
- realm, msg_handler, msg_handler_data, &winner);
+ done = service_fds(context, sel_state, delay, timeout, conns,
+ seltemp, realm, msg_handler, msg_handler_data,
+ &winner);
}
if (sel_state->nfds == 0)
break;
--
2.46.0

View file

@ -1,138 +0,0 @@
From 1da153d97d7fb30a44fca35f9b71b8f4ed5385b9 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
When making a KDC or password change request, wait indefinitely
(limited only by request_timeout if set) once a KDC has accepted a TCP
connection.
ticket: 9105 (new)
(cherry picked from commit 6436a3808061da787a43c6810f5f0370cdfb6e36)
---
doc/admin/conf_files/krb5_conf.rst | 2 +-
src/lib/krb5/os/sendto_kdc.c | 50 ++++++++++++++++--------------
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
--- 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:
for initial ticket requests. The default value is 0.
**request_timeout**
- (:ref:`duration` string.) Sets the maximum total time for KDC or
+ (:ref:`duration` string.) Sets the maximum total time for KDC and
password change requests. This timeout does not affect the
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
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -134,7 +134,6 @@ struct conn_state {
krb5_data callback_buffer;
size_t server_index;
struct conn_state *next;
- time_ms endtime;
krb5_boolean defer;
struct {
const char *uri_path;
@@ -344,15 +343,19 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
struct select_state *out, int *sret)
{
#ifndef USE_POLL
- struct timeval tv;
+ struct timeval tv, *tvp;
#endif
krb5_error_code retval;
time_ms curtime, interval;
- retval = get_curtime_ms(&curtime);
- if (retval != 0)
- return retval;
- interval = (curtime < endtime) ? endtime - curtime : 0;
+ if (endtime != 0) {
+ retval = get_curtime_ms(&curtime);
+ if (retval != 0)
+ return retval;
+ interval = (curtime < endtime) ? endtime - curtime : 0;
+ } else {
+ interval = -1;
+ }
/* We don't need a separate copy of the selstate for poll, but use one for
* consistency with how we use select. */
@@ -361,9 +364,14 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
#ifdef USE_POLL
*sret = poll(out->fds, out->nfds, interval);
#else
- tv.tv_sec = interval / 1000;
- tv.tv_usec = interval % 1000 * 1000;
- *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, &tv);
+ if (interval != -1) {
+ tv.tv_sec = interval / 1000;
+ tv.tv_usec = interval % 1000 * 1000;
+ tvp = &tv;
+ } else {
+ tvp = NULL;
+ }
+ *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, tvp);
#endif
return (*sret < 0) ? SOCKET_ERRNO : 0;
@@ -1099,11 +1107,6 @@ service_tcp_connect(krb5_context context, const krb5_data *realm,
}
conn->state = WRITING;
-
- /* Record this connection's timeout for service_fds. */
- if (get_curtime_ms(&conn->endtime) == 0)
- conn->endtime += 10000;
-
return conn->service_write(context, realm, conn, selstate);
}
@@ -1378,19 +1381,18 @@ kill_conn:
return FALSE;
}
-/* Return the maximum of endtime and the endtime fields of all currently active
- * TCP connections. */
-static time_ms
-get_endtime(time_ms endtime, struct conn_state *conns)
+/* Return true if conns contains any states with connected TCP sockets. */
+static krb5_boolean
+any_tcp_connections(struct conn_state *conns)
{
struct conn_state *state;
for (state = conns; state != NULL; state = state->next) {
- if ((state->state == READING || state->state == WRITING) &&
- state->endtime > endtime)
- endtime = state->endtime;
+ if (state->addr.transport != UDP &&
+ (state->state == READING || state->state == WRITING))
+ return TRUE;
}
- return endtime;
+ return FALSE;
}
static krb5_boolean
@@ -1413,9 +1415,9 @@ service_fds(krb5_context context, struct select_state *selstate,
e = 0;
while (selstate->nfds > 0) {
- endtime = get_endtime(interval_end, conns);
+ endtime = any_tcp_connections(conns) ? 0 : interval_end;
/* Don't wait longer than the whole request should last. */
- if (timeout && endtime > timeout)
+ if (timeout && (!endtime || endtime > timeout))
endtime = timeout;
e = cm_select_or_poll(selstate, endtime, seltemp, &selret);
if (e == EINTR)
--
2.46.0

File diff suppressed because it is too large Load diff

View file

@ -1,265 +0,0 @@
From 3999883b9745bfd7065d41ff05b19e56bcb2e791 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
In klists's show_credential(), ensure that the column counter doesn't
decrease if printf() fails.
In process_k5beta7_princ(), bounds-check the e_length field.
In ndr_enc_delegation_info(), initialize b so it is always valid for
the cleanup handler.
In krb5_dbe_def_decrypt_key_data(), change the flow control so ret is
always set by the end of the function. Return KRB5_KDB_INVALIDKEYSIZE
if there isn't enough data in the first key_data_contents field or if
the serialized key length is invalid.
In svcauth_gss_validate(), expand rpchdr to accomodate the header plus
MAX_AUTH_BYTES.
In svcudp_reply(), change slen to unsigned to match the return type of
XDR_GETPOS() and eliminate an unnecessary check for slen >= 0.
In krb5int_pthread_loaded()(), remove pthread_equal() from the weak
symbol checks. It is implemented as an inline function in some glibc
versions, which makes the comparison "&pthread_equal == 0" always
false.
[ghudson@mit.edu: further modified krb5_dbe_def_decrypt_key_data() for
clarity; added detail to commit message]
(cherry picked from commit a96541981ee34c8642ddeb6101b98e883e41c6e5)
---
src/clients/klist/klist.c | 12 ++++-----
src/kadmin/dbutil/dump.c | 5 ++++
src/kdc/ndr.c | 2 +-
src/lib/kdb/decrypt_key.c | 54 ++++++++++++++++++++------------------
src/lib/rpc/svc_auth_gss.c | 5 +++-
src/lib/rpc/svc_udp.c | 13 ++++-----
src/util/support/threads.c | 2 --
7 files changed, 51 insertions(+), 42 deletions(-)
diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c
index b5808e5c93..ba9539fd23 100644
--- a/src/clients/klist/klist.c
+++ b/src/clients/klist/klist.c
@@ -681,7 +681,7 @@ show_credential(krb5_creds *cred, const char *defname)
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);
@@ -711,11 +711,11 @@ show_credential(krb5_creds *cred, const char *defname)
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..21aa3742b1 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();
@@ -74,36 +74,38 @@ krb5_dbe_def_decrypt_key_data(krb5_context context, const krb5_keyblock *mkey,
if (mkey == NULL)
return KRB5_KDB_BADSTORED_MKEY;
- if (kd->key_data_contents[0] != NULL && kd->key_data_length[0] >= 2) {
- keylen = load_16_le(kd->key_data_contents[0]);
- if (keylen < 0)
- return EINVAL;
- cipher.enctype = ENCTYPE_UNKNOWN;
- cipher.ciphertext = make_data(kd->key_data_contents[0] + 2,
- kd->key_data_length[0] - 2);
- ret = alloc_data(&plain, kd->key_data_length[0] - 2);
- if (ret)
- goto cleanup;
+ if (kd->key_data_contents[0] == NULL || kd->key_data_length[0] < 2)
+ return KRB5_KDB_INVALIDKEYSIZE;
- ret = krb5_c_decrypt(context, mkey, 0, 0, &cipher, &plain);
- if (ret)
- goto cleanup;
+ keylen = load_16_le(kd->key_data_contents[0]);
+ if (keylen < 0)
+ return KRB5_KDB_INVALIDKEYSIZE;
- /* Make sure the plaintext has at least as many bytes as the true ke
- * length (it may have more due to padding). */
- if ((unsigned int)keylen > plain.length) {
- ret = KRB5_CRYPTO_INTERNAL;
- if (ret)
- goto cleanup;
- }
+ cipher.enctype = ENCTYPE_UNKNOWN;
+ cipher.ciphertext = make_data(kd->key_data_contents[0] + 2,
+ kd->key_data_length[0] - 2);
+ ret = alloc_data(&plain, kd->key_data_length[0] - 2);
+ if (ret)
+ goto cleanup;
- kb.magic = KV5M_KEYBLOCK;
- kb.enctype = kd->key_data_type[0];
- kb.length = keylen;
- kb.contents = (uint8_t *)plain.data;
- plain = empty_data();
+ ret = krb5_c_decrypt(context, mkey, 0, 0, &cipher, &plain);
+ if (ret)
+ goto cleanup;
+
+ /* Make sure the plaintext has at least as many bytes as the true key
+ * length (it may have more due to padding). */
+ if ((unsigned int)keylen > plain.length) {
+ ret = KRB5_CRYPTO_INTERNAL;
+ if (ret)
+ goto cleanup;
}
+ kb.magic = KV5M_KEYBLOCK;
+ kb.enctype = kd->key_data_type[0];
+ kb.length = keylen;
+ kb.contents = (uint8_t *)plain.data;
+ plain = empty_data();
+
/* Decode salt data. */
if (keysalt_out != NULL) {
if (kd->key_data_ver == 2) {
diff --git a/src/lib/rpc/svc_auth_gss.c b/src/lib/rpc/svc_auth_gss.c
index 98d601c8ab..4f1d2911b0 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

View file

@ -1,629 +0,0 @@
From ea02fd7bb79861b8e36517c7c95af821a16657c4 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
Implement some of the measures specified in
draft-ietf-radext-deprecating-radius-03 for mitigating the BlastRADIUS
attack (CVE-2024-3596):
* Include a Message-Authenticator MAC as the first attribute when
generating a packet of type Access-Request, Access-Reject,
Access-Accept, or Access-Challenge (sections 5.2.1 and 5.2.4), if
the secret is non-empty. (An empty secret indicates the use of Unix
domain socket transport.)
* Validate the Message-Authenticator MAC in received packets, if
present.
FreeRADIUS enforces Message-Authenticator as of versions 3.2.5 and
3.0.27. libkrad must generate Message-Authenticator attributes in
order to remain compatible with these implementations.
[ghudson@mit.edu: adjusted style and naming; simplified some
functions; edited commit message]
ticket: 9142 (new)
tags: pullup
target_version: 1.21-next
(cherry picked from commit 871125fea8ce0370a972bf65f7d1de63f619b06c)
---
src/include/k5-int.h | 5 +
src/lib/crypto/krb/checksum_hmac_md5.c | 28 ++++
src/lib/crypto/libk5crypto.exports | 1 +
src/lib/krad/attr.c | 17 ++
src/lib/krad/attrset.c | 59 +++++--
src/lib/krad/internal.h | 7 +-
src/lib/krad/packet.c | 206 +++++++++++++++++++++++--
src/lib/krad/t_attrset.c | 2 +-
src/lib/krad/t_daemon.py | 3 +-
src/lib/krad/t_packet.c | 11 ++
src/tests/t_otp.py | 3 +
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
--- 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);
+/* Generate an HMAC-MD5 keyed checksum as specified by RFC 2104. */
+krb5_error_code
+k5_hmac_md5(const krb5_data *key, const krb5_crypto_iov *data, size_t num_data,
+ krb5_data *output);
+
#endif /* _KRB5_INT_H */
diff --git a/src/lib/crypto/krb/checksum_hmac_md5.c b/src/lib/crypto/krb/checksum_hmac_md5.c
index ec024f3966..a809388549 100644
--- a/src/lib/crypto/krb/checksum_hmac_md5.c
+++ b/src/lib/crypto/krb/checksum_hmac_md5.c
@@ -92,3 +92,31 @@ cleanup:
free(hash_iov);
return ret;
}
+
+krb5_error_code
+k5_hmac_md5(const krb5_data *key, const krb5_crypto_iov *data, size_t num_data,
+ krb5_data *output)
+{
+ krb5_error_code ret;
+ const struct krb5_hash_provider *hash = &krb5int_hash_md5;
+ krb5_keyblock keyblock = { 0 };
+ krb5_data hashed_key;
+ uint8_t hkeybuf[16];
+ krb5_crypto_iov iov;
+
+ /* Hash the key if it is longer than the block size. */
+ if (key->length > hash->blocksize) {
+ hashed_key = make_data(hkeybuf, sizeof(hkeybuf));
+ iov.flags = KRB5_CRYPTO_TYPE_DATA;
+ iov.data = *key;
+ ret = hash->hash(&iov, 1, &hashed_key);
+ if (ret)
+ return ret;
+ key = &hashed_key;
+ }
+
+ keyblock.magic = KV5M_KEYBLOCK;
+ keyblock.length = key->length;
+ keyblock.contents = (uint8_t *)key->data;
+ 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
--- a/src/lib/crypto/libk5crypto.exports
+++ b/src/lib/crypto/libk5crypto.exports
@@ -102,3 +102,4 @@ krb5_c_prfplus
krb5_c_derive_prfplus
k5_enctype_to_ssf
krb5int_c_deprecated_enctype
+k5_hmac_md5
diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
index 42d354a3b5..65ed1d35e7 100644
--- a/src/lib/krad/attr.c
+++ b/src/lib/krad/attr.c
@@ -125,6 +125,23 @@ static const attribute_record attributes[UCHAR_MAX] = {
{"NAS-Port-Type", 4, 4, NULL, NULL},
{"Port-Limit", 4, 4, NULL, NULL},
{"Login-LAT-Port", 1, MAX_ATTRSIZE, NULL, NULL},
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
+ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
+ {NULL, 0, 0, NULL, NULL}, /* Password-Retry */
+ {NULL, 0, 0, NULL, NULL}, /* Prompt */
+ {NULL, 0, 0, NULL, NULL}, /* Connect-Info */
+ {NULL, 0, 0, NULL, NULL}, /* Configuration-Token */
+ {NULL, 0, 0, NULL, NULL}, /* EAP-Message */
+ {"Message-Authenticator", MD5_DIGEST_SIZE, MD5_DIGEST_SIZE, NULL, NULL},
};
/* Encode User-Password attribute. */
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
index 6ec031e320..e5457ebfd7 100644
--- a/src/lib/krad/attrset.c
+++ b/src/lib/krad/attrset.c
@@ -164,15 +164,44 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
return 0;
}
+/* Place an encoded attributes into outbuf at position *i. Increment *i by the
+ * length of the encoding. */
+static krb5_error_code
+append_attr(krb5_context ctx, const char *secret,
+ const uint8_t *auth, krad_attr type, const krb5_data *data,
+ uint8_t outbuf[MAX_ATTRSETSIZE], size_t *i, krb5_boolean *is_fips)
+{
+ uint8_t buffer[MAX_ATTRSIZE];
+ size_t attrlen;
+ krb5_error_code retval;
+
+ retval = kr_attr_encode(ctx, secret, auth, type, data, buffer, &attrlen,
+ is_fips);
+ if (retval)
+ return retval;
+
+ if (attrlen > MAX_ATTRSETSIZE - *i - 2)
+ return EMSGSIZE;
+
+ outbuf[(*i)++] = type;
+ outbuf[(*i)++] = attrlen + 2;
+ memcpy(outbuf + *i, buffer, attrlen);
+ *i += attrlen;
+
+ return 0;
+}
+
krb5_error_code
kr_attrset_encode(const krad_attrset *set, const char *secret,
- const unsigned char *auth,
+ const uint8_t *auth, krb5_boolean add_msgauth,
unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
krb5_boolean *is_fips)
{
- unsigned char buffer[MAX_ATTRSIZE];
krb5_error_code retval;
- size_t i = 0, attrlen;
+ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
+ const uint8_t zeroes[MD5_DIGEST_SIZE] = { 0 };
+ krb5_data zerodata;
+ size_t i = 0;
attr *a;
if (set == NULL) {
@@ -180,19 +209,21 @@ kr_attrset_encode(const krad_attrset *set, const char *secret,
return 0;
}
- K5_TAILQ_FOREACH(a, &set->list, list) {
- retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
- buffer, &attrlen, is_fips);
- if (retval != 0)
+ if (add_msgauth) {
+ /* Encode Message-Authenticator as the first attribute, per
+ * draft-ietf-radext-deprecating-radius-03 section 5.2. */
+ zerodata = make_data((uint8_t *)zeroes, MD5_DIGEST_SIZE);
+ retval = append_attr(set->ctx, secret, auth, msgauth_type, &zerodata,
+ outbuf, &i, is_fips);
+ if (retval)
return retval;
+ }
- if (i + attrlen + 2 > MAX_ATTRSETSIZE)
- return EMSGSIZE;
-
- outbuf[i++] = a->type;
- outbuf[i++] = attrlen + 2;
- memcpy(&outbuf[i], buffer, attrlen);
- i += attrlen;
+ K5_TAILQ_FOREACH(a, &set->list, list) {
+ retval = append_attr(set->ctx, secret, auth, a->type, &a->attr,
+ outbuf, &i, is_fips);
+ if (retval)
+ return retval;
}
*outlen = i;
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
index a17b6f39b1..ca66f3ec68 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -49,6 +49,8 @@
#define UCHAR_MAX 255
#endif
+#define MD5_DIGEST_SIZE 16
+
/* 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,
krad_attr type, const krb5_data *in,
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
-/* Encode the attributes into the buffer. */
+/* Encode set into outbuf. If add_msgauth is true, include a zeroed
+ * Message-Authenticator as the first attribute. */
krb5_error_code
kr_attrset_encode(const krad_attrset *set, const char *secret,
- const unsigned char *auth,
+ const uint8_t *auth, krb5_boolean add_msgauth,
unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
krb5_boolean *is_fips);
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
index c5446b890c..3c1a4d507e 100644
--- a/src/lib/krad/packet.c
+++ b/src/lib/krad/packet.c
@@ -36,6 +36,7 @@
typedef unsigned char uchar;
/* RFC 2865 */
+#define MSGAUTH_SIZE (2 + MD5_DIGEST_SIZE)
#define OFFSET_CODE 0
#define OFFSET_ID 1
#define OFFSET_LENGTH 2
@@ -222,6 +223,106 @@ packet_set_attrset(krb5_context ctx, const char *secret, krad_packet *pkt)
return kr_attrset_decode(ctx, &tmp, secret, pkt_auth(pkt), &pkt->attrset);
}
+/* Determine if a packet requires a Message-Authenticator attribute. */
+static inline krb5_boolean
+requires_msgauth(const char *secret, krad_code code)
+{
+ /* If no secret is provided, assume that the transport is a UNIX socket.
+ * Message-Authenticator is required only on UDP and TCP connections. */
+ if (*secret == '\0')
+ return FALSE;
+
+ /*
+ * Per draft-ietf-radext-deprecating-radius-03 sections 5.2.1 and 5.2.4,
+ * Message-Authenticator is required in Access-Request packets and all
+ * potential responses when UDP or TCP transport is used.
+ */
+ return code == krad_code_name2num("Access-Request") ||
+ code == krad_code_name2num("Access-Reject") ||
+ code == krad_code_name2num("Access-Accept") ||
+ code == krad_code_name2num("Access-Challenge");
+}
+
+/* Check if the packet has a Message-Authenticator attribute. */
+static inline krb5_boolean
+has_pkt_msgauth(const krad_packet *pkt)
+{
+ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
+
+ return krad_attrset_get(pkt->attrset, msgauth_type, 0) != NULL;
+}
+
+/* Return the beginning of the Message-Authenticator attribute in pkt, or NULL
+ * if no such attribute is present. */
+static const uint8_t *
+lookup_msgauth_addr(const krad_packet *pkt)
+{
+ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
+ size_t i;
+ uint8_t *p;
+
+ i = OFFSET_ATTR;
+ while (i + 2 < pkt->pkt.length) {
+ p = (uint8_t *)offset(&pkt->pkt, i);
+ if (msgauth_type == *p)
+ return p;
+ i += p[1];
+ }
+
+ return NULL;
+}
+
+/*
+ * Calculate the message authenticator MAC for pkt as specified in RFC 2869
+ * section 5.14, placing the result in mac_out. Use the provided authenticator
+ * auth, which may be from pkt or from a corresponding request.
+ */
+static krb5_error_code
+calculate_mac(const char *secret, const krad_packet *pkt,
+ const uint8_t auth[AUTH_FIELD_SIZE],
+ uint8_t mac_out[MD5_DIGEST_SIZE])
+{
+ uint8_t zeroed_msgauth[MSGAUTH_SIZE];
+ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
+ const uint8_t *msgauth_attr, *msgauth_end, *pkt_end;
+ krb5_crypto_iov input[5];
+ krb5_data ksecr, mac;
+
+ msgauth_attr = lookup_msgauth_addr(pkt);
+ if (msgauth_attr == NULL)
+ return EINVAL;
+ msgauth_end = msgauth_attr + MSGAUTH_SIZE;
+ pkt_end = (const uint8_t *)pkt->pkt.data + pkt->pkt.length;
+
+ /* Read code, id, and length from the packet. */
+ input[0].flags = KRB5_CRYPTO_TYPE_DATA;
+ input[0].data = make_data(pkt->pkt.data, OFFSET_AUTH);
+
+ /* Read the provided authenticator. */
+ input[1].flags = KRB5_CRYPTO_TYPE_DATA;
+ input[1].data = make_data((uint8_t *)auth, AUTH_FIELD_SIZE);
+
+ /* Read any attributes before Message-Authenticator. */
+ input[2].flags = KRB5_CRYPTO_TYPE_DATA;
+ input[2].data = make_data(pkt_attr(pkt), msgauth_attr - pkt_attr(pkt));
+
+ /* Read Message-Authenticator with the data bytes all set to zero, per RFC
+ * 2869 section 5.14. */
+ zeroed_msgauth[0] = msgauth_type;
+ zeroed_msgauth[1] = MSGAUTH_SIZE;
+ memset(zeroed_msgauth + 2, 0, MD5_DIGEST_SIZE);
+ input[3].flags = KRB5_CRYPTO_TYPE_DATA;
+ input[3].data = make_data(zeroed_msgauth, MSGAUTH_SIZE);
+
+ /* Read any attributes after Message-Authenticator. */
+ input[4].flags = KRB5_CRYPTO_TYPE_DATA;
+ input[4].data = make_data((uint8_t *)msgauth_end, pkt_end - msgauth_end);
+
+ mac = make_data(mac_out, MD5_DIGEST_SIZE);
+ ksecr = string2data((char *)secret);
+ return k5_hmac_md5(&ksecr, input, 5, &mac);
+}
+
ssize_t
krad_packet_bytes_needed(const krb5_data *buffer)
{
@@ -255,6 +356,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
krad_packet *pkt;
uchar id;
size_t attrset_len;
+ krb5_boolean msgauth_required;
pkt = packet_new();
if (pkt == NULL) {
@@ -274,9 +376,13 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
if (retval != 0)
goto error;
+ /* Determine if Message-Authenticator is required. */
+ msgauth_required = (*secret != '\0' &&
+ code == krad_code_name2num("Access-Request"));
+
/* Encode the attributes. */
- retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt),
- &attrset_len, &pkt->is_fips);
+ retval = kr_attrset_encode(set, secret, pkt_auth(pkt), msgauth_required,
+ pkt_attr(pkt), &attrset_len, &pkt->is_fips);
if (retval != 0)
goto error;
@@ -285,6 +391,13 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
pkt_code_set(pkt, code);
pkt_len_set(pkt, pkt->pkt.length);
+ if (msgauth_required) {
+ /* Calculate and set the Message-Authenticator MAC. */
+ retval = calculate_mac(secret, pkt, pkt_auth(pkt), pkt_attr(pkt) + 2);
+ if (retval != 0)
+ goto error;
+ }
+
/* Copy the attrset for future use. */
retval = packet_set_attrset(ctx, secret, pkt);
if (retval != 0)
@@ -307,14 +420,19 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
krb5_error_code retval;
krad_packet *pkt;
size_t attrset_len;
+ krb5_boolean msgauth_required;
pkt = packet_new();
if (pkt == NULL)
return ENOMEM;
+ /* Determine if Message-Authenticator is required. */
+ msgauth_required = requires_msgauth(secret, code);
+
/* Encode the attributes. */
- retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt),
- &attrset_len, &pkt->is_fips);
+ retval = kr_attrset_encode(set, secret, pkt_auth(request),
+ msgauth_required, pkt_attr(pkt), &attrset_len,
+ &pkt->is_fips);
if (retval != 0)
goto error;
@@ -330,6 +448,18 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
if (retval != 0)
goto error;
+ if (msgauth_required) {
+ /*
+ * Calculate and replace the Message-Authenticator MAC. Per RFC 2869
+ * section 5.14, use the authenticator from the request, not from the
+ * response.
+ */
+ retval = calculate_mac(secret, pkt, pkt_auth(request),
+ pkt_attr(pkt) + 2);
+ if (retval != 0)
+ goto error;
+ }
+
/* Copy the attrset for future use. */
retval = packet_set_attrset(ctx, secret, pkt);
if (retval != 0)
@@ -343,6 +473,34 @@ error:
return retval;
}
+/* Verify the Message-Authenticator value in pkt, using the provided
+ * authenticator (which may be from pkt or from a corresponding request). */
+static krb5_error_code
+verify_msgauth(const char *secret, const krad_packet *pkt,
+ const uint8_t auth[AUTH_FIELD_SIZE])
+{
+ uint8_t mac[MD5_DIGEST_SIZE];
+ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator");
+ const krb5_data *msgauth;
+ krb5_error_code retval;
+
+ msgauth = krad_packet_get_attr(pkt, msgauth_type, 0);
+ if (msgauth == NULL)
+ return ENODATA;
+
+ retval = calculate_mac(secret, pkt, auth, mac);
+ if (retval)
+ return retval;
+
+ if (msgauth->length != MD5_DIGEST_SIZE)
+ return EMSGSIZE;
+
+ if (k5_bcmp(mac, msgauth->data, MD5_DIGEST_SIZE) != 0)
+ return EBADMSG;
+
+ return 0;
+}
+
/* Decode a packet. */
static krb5_error_code
decode_packet(krb5_context ctx, const char *secret, const krb5_data *buffer,
@@ -394,21 +552,35 @@ krad_packet_decode_request(krb5_context ctx, const char *secret,
krad_packet **reqpkt)
{
const krad_packet *tmp = NULL;
+ krad_packet *req;
krb5_error_code retval;
- retval = decode_packet(ctx, secret, buffer, reqpkt);
- if (cb != NULL && retval == 0) {
+ retval = decode_packet(ctx, secret, buffer, &req);
+ if (retval)
+ return retval;
+
+ /* Verify Message-Authenticator if present. */
+ if (has_pkt_msgauth(req)) {
+ retval = verify_msgauth(secret, req, pkt_auth(req));
+ if (retval) {
+ krad_packet_free(req);
+ return retval;
+ }
+ }
+
+ if (cb != NULL) {
for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) {
if (pkt_id_get(*reqpkt) == pkt_id_get(tmp))
break;
}
- }
- if (cb != NULL && (retval != 0 || tmp != NULL))
- (*cb)(data, TRUE);
+ if (tmp != NULL)
+ (*cb)(data, TRUE);
+ }
+ *reqpkt = req;
*duppkt = tmp;
- return retval;
+ return 0;
}
krb5_error_code
@@ -435,9 +607,17 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
break;
}
- /* If the authenticator matches, then the response is valid. */
- if (memcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) == 0)
- break;
+ /* Verify the response authenticator. */
+ if (k5_bcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) != 0)
+ continue;
+
+ /* Verify Message-Authenticator if present. */
+ if (has_pkt_msgauth(*rsppkt)) {
+ if (verify_msgauth(secret, *rsppkt, pkt_auth(tmp)) != 0)
+ continue;
+ }
+
+ break;
}
}
diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
index 4cdb8b7d8e..f9c66509bd 100644
--- a/src/lib/krad/t_attrset.c
+++ b/src/lib/krad/t_attrset.c
@@ -63,7 +63,7 @@ main(void)
noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp));
/* Encode attrset. */
- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len,
+ noerror(kr_attrset_encode(set, "foo", auth, FALSE, buffer, &encode_len,
&is_fips));
krad_attrset_free(set);
diff --git a/src/lib/krad/t_daemon.py b/src/lib/krad/t_daemon.py
index 4a3de079c7..647d4894eb 100755
--- a/src/lib/krad/t_daemon.py
+++ b/src/lib/krad/t_daemon.py
@@ -40,6 +40,7 @@ DICTIONARY = """
ATTRIBUTE\tUser-Name\t1\tstring
ATTRIBUTE\tUser-Password\t2\toctets
ATTRIBUTE\tNAS-Identifier\t32\tstring
+ATTRIBUTE\tMessage-Authenticator\t80\toctets
"""
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]]
- reply = self.CreateReplyPacket(pkt)
+ reply = self.CreateReplyPacket(pkt, message_authenticator=True)
if passwd == ['accept']:
reply.code = packet.AccessAccept
else:
diff --git a/src/lib/krad/t_packet.c b/src/lib/krad/t_packet.c
index c22489144f..104b6507a2 100644
--- a/src/lib/krad/t_packet.c
+++ b/src/lib/krad/t_packet.c
@@ -172,6 +172,9 @@ main(int argc, const char **argv)
krb5_data username, password;
krb5_boolean auth = FALSE;
krb5_context ctx;
+ const krad_packet *dupreq;
+ const krb5_data *encpkt;
+ krad_packet *decreq;
username = string2data("testUser");
@@ -184,9 +187,17 @@ main(int argc, const char **argv)
password = string2data("accept");
noerror(make_packet(ctx, &username, &password, &packets[ACCEPT_PACKET]));
+ encpkt = krad_packet_encode(packets[ACCEPT_PACKET]);
+ noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL,
+ &dupreq, &decreq));
+ krad_packet_free(decreq);
password = string2data("reject");
noerror(make_packet(ctx, &username, &password, &packets[REJECT_PACKET]));
+ encpkt = krad_packet_encode(packets[REJECT_PACKET]);
+ noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL,
+ &dupreq, &decreq));
+ krad_packet_free(decreq);
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
--- a/src/tests/t_otp.py
+++ b/src/tests/t_otp.py
@@ -49,6 +49,7 @@ ATTRIBUTE User-Name 1 string
ATTRIBUTE User-Password 2 octets
ATTRIBUTE Service-Type 6 integer
ATTRIBUTE NAS-Identifier 32 string
+ATTRIBUTE Message-Authenticator 80 octets
'''
class RadiusDaemon(Process):
@@ -97,6 +98,8 @@ class RadiusDaemon(Process):
reply.code = packet.AccessReject
replyq['reply'] = False
+ reply.add_message_authenticator()
+
outq.put(replyq)
if addr is None:
sock.send(reply.ReplyPacket())
--
2.46.0

File diff suppressed because it is too large Load diff

View file

@ -1,78 +0,0 @@
From 43d10f1580c033fe706470e7588c720ac7854918 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 21 Jun 2023 18:27:11 +0200
Subject: [PATCH] Add ecdsa-with-sha512/256 to supportedCMSTypes
Elliptic curve certificates are already supported for PKINIT
pre-authentication, but their associated signature types aren't
advertized. Add ecdsa-with-sha512 and ecdsa-with-sha256 OIDs to the
supportedCMSTypes list sent by the client.
[ghudson@mit.edu: edited commit message]
ticket: 9100 (new)
(cherry picked from commit 9913e5c92c4e5cb76d6ae58386f744766d2e6454)
---
src/plugins/preauth/pkinit/pkinit_constants.c | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/src/plugins/preauth/pkinit/pkinit_constants.c b/src/plugins/preauth/pkinit/pkinit_constants.c
index 10f8688ec2..905e90d29c 100644
--- a/src/plugins/preauth/pkinit/pkinit_constants.c
+++ b/src/plugins/preauth/pkinit/pkinit_constants.c
@@ -64,14 +64,52 @@ static char sha512WithRSAEncr_oid[9] = {
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d
};
+/* RFC 3279 ecdsa-with-SHA1: iso(1) member-body(2) us(840) ansi-X9-62(10045)
+ * signatures(4) 1 */
+static char ecdsaWithSha1_oid[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01
+};
+
+/* RFC 5758 ecdsa-with-SHA256: iso(1) member-body(2) us(840) ansi-X9-62(10045)
+ * signatures(4) ecdsa-with-SHA2(3) 2 */
+static char ecdsaWithSha256_oid[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02
+};
+
+/* RFC 5758 ecdsa-with-SHA384: iso(1) member-body(2) us(840) ansi-X9-62(10045)
+ * signatures(4) ecdsa-with-SHA2(3) 3 */
+static char ecdsaWithSha384_oid[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03
+};
+
+/* RFC 5758 ecdsa-with-SHA512: iso(1) member-body(2) us(840) ansi-X9-62(10045)
+ * signatures(4) ecdsa-with-SHA2(3) 4 */
+static char ecdsaWithSha512_oid[] = {
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04
+};
+
const krb5_data sha256WithRSAEncr_id = {
KV5M_DATA, sizeof(sha256WithRSAEncr_oid), sha256WithRSAEncr_oid
};
const krb5_data sha512WithRSAEncr_id = {
KV5M_DATA, sizeof(sha512WithRSAEncr_oid), sha512WithRSAEncr_oid
};
+const krb5_data ecdsaWithSha1_id = {
+ KV5M_DATA, sizeof(ecdsaWithSha1_oid), ecdsaWithSha1_oid
+};
+const krb5_data ecdsaWithSha256_id = {
+ KV5M_DATA, sizeof(ecdsaWithSha256_oid), ecdsaWithSha256_oid
+};
+const krb5_data ecdsaWithSha384_id = {
+ KV5M_DATA, sizeof(ecdsaWithSha384_oid), ecdsaWithSha384_oid
+};
+const krb5_data ecdsaWithSha512_id = {
+ KV5M_DATA, sizeof(ecdsaWithSha512_oid), ecdsaWithSha512_oid
+};
krb5_data const * const supported_cms_algs[] = {
+ &ecdsaWithSha512_id,
+ &ecdsaWithSha256_id,
&sha512WithRSAEncr_id,
&sha256WithRSAEncr_id,
NULL
--
2.47.1

View file

@ -1,264 +0,0 @@
From fba4cbf0bc50569b8ea6d1e1c3303eaab84935e1 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sun, 30 Jul 2023 01:07:38 -0400
Subject: [PATCH] Get rid of pkinit_crypto_openssl.h
Fold pkinit_crypto_openssl.h into the one source file where it was
used. Also clean up the include of <arpa/inet.h>, as htonl() is no
longer used after commit 1c87ce6c44a9de0824580a2d72a8a202237e01f4.
(cherry picked from commit b3352945fb8836f8b4095e0b8aad04b54aca3152)
---
src/plugins/preauth/pkinit/deps | 2 +-
.../preauth/pkinit/pkinit_crypto_openssl.c | 85 +++++++++++-
.../preauth/pkinit/pkinit_crypto_openssl.h | 121 ------------------
3 files changed, 83 insertions(+), 125 deletions(-)
delete mode 100644 src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
diff --git a/src/plugins/preauth/pkinit/deps b/src/plugins/preauth/pkinit/deps
index 58320aa801..b6f4476fe8 100644
--- a/src/plugins/preauth/pkinit/deps
+++ b/src/plugins/preauth/pkinit/deps
@@ -112,4 +112,4 @@ pkinit_crypto_openssl.so pkinit_crypto_openssl.po $(OUTPRE)pkinit_crypto_openssl
$(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \
$(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
pkcs11.h pkinit.h pkinit_accessor.h pkinit_crypto.h \
- pkinit_crypto_openssl.c pkinit_crypto_openssl.h pkinit_trace.h
+ pkinit_crypto_openssl.c pkinit_trace.h
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index f6d494bd11..ae8599d5a2 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -30,20 +30,99 @@
*/
#include "k5-int.h"
-#include "pkinit_crypto_openssl.h"
#include "k5-buf.h"
#include "k5-err.h"
#include "k5-hex.h"
-#include <unistd.h>
+#include "pkinit.h"
#include <dirent.h>
-#include <arpa/inet.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/x509.h>
+#include <openssl/pkcs7.h>
+#include <openssl/pkcs12.h>
+#include <openssl/obj_mac.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <openssl/asn1.h>
+#include <openssl/pem.h>
+#include <openssl/asn1t.h>
+#include <openssl/cms.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/core_names.h>
#include <openssl/kdf.h>
+#include <openssl/decoder.h>
#include <openssl/params.h>
#endif
+#define DN_BUF_LEN 256
+#define MAX_CREDS_ALLOWED 20
+
+struct _pkinit_cred_info {
+ char *name;
+ X509 *cert;
+ EVP_PKEY *key;
+#ifndef WITHOUT_PKCS11
+ CK_BYTE_PTR cert_id;
+ int cert_id_len;
+#endif
+};
+typedef struct _pkinit_cred_info *pkinit_cred_info;
+
+struct _pkinit_identity_crypto_context {
+ pkinit_cred_info creds[MAX_CREDS_ALLOWED+1];
+ STACK_OF(X509) *my_certs; /* available user certs */
+ char *identity; /* identity name for user cert */
+ int cert_index; /* cert to use out of available certs*/
+ EVP_PKEY *my_key; /* available user keys if in filesystem */
+ STACK_OF(X509) *trustedCAs; /* available trusted ca certs */
+ STACK_OF(X509) *intermediateCAs; /* available intermediate ca certs */
+ STACK_OF(X509_CRL) *revoked; /* available crls */
+ int pkcs11_method;
+ krb5_prompter_fct prompter;
+ void *prompter_data;
+#ifndef WITHOUT_PKCS11
+ char *p11_module_name;
+ CK_SLOT_ID slotid;
+ char *token_label;
+ char *cert_label;
+ /* These are crypto-specific. */
+ struct plugin_file_handle *p11_module;
+ CK_SESSION_HANDLE session;
+ CK_FUNCTION_LIST_PTR p11;
+ uint8_t *cert_id;
+ size_t cert_id_len;
+ CK_MECHANISM_TYPE mech;
+#endif
+ krb5_boolean defer_id_prompt;
+ pkinit_deferred_id *deferred_ids;
+};
+
+struct _pkinit_plg_crypto_context {
+ EVP_PKEY *dh_1024;
+ EVP_PKEY *dh_2048;
+ EVP_PKEY *dh_4096;
+ EVP_PKEY *ec_p256;
+ EVP_PKEY *ec_p384;
+ EVP_PKEY *ec_p521;
+ ASN1_OBJECT *id_pkinit_authData;
+ ASN1_OBJECT *id_pkinit_DHKeyData;
+ ASN1_OBJECT *id_pkinit_rkeyData;
+ ASN1_OBJECT *id_pkinit_san;
+ ASN1_OBJECT *id_ms_san_upn;
+ ASN1_OBJECT *id_pkinit_KPClientAuth;
+ ASN1_OBJECT *id_pkinit_KPKdc;
+ ASN1_OBJECT *id_ms_kp_sc_logon;
+ ASN1_OBJECT *id_kp_serverAuth;
+};
+
+struct _pkinit_req_crypto_context {
+ X509 *received_cert;
+ EVP_PKEY *client_pkey;
+};
+
static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context );
static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context );
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
deleted file mode 100644
index b7a3358800..0000000000
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * COPYRIGHT (C) 2006,2007
- * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
- * ALL RIGHTS RESERVED
- *
- * Permission is granted to use, copy, create derivative works
- * and redistribute this software and such derivative works
- * for any purpose, so long as the name of The University of
- * Michigan is not used in any advertising or publicity
- * pertaining to the use of distribution of this software
- * without specific, written prior authorization. If the
- * above copyright notice or any other identification of the
- * University of Michigan is included in any copy of any
- * portion of this software, then the disclaimer below must
- * also be included.
- *
- * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
- * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
- * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
- * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
- * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
- * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
- * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
- * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
- * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGES.
- */
-
-#ifndef _PKINIT_CRYPTO_OPENSSL_H
-#define _PKINIT_CRYPTO_OPENSSL_H
-
-#include "pkinit.h"
-
-#include <openssl/bn.h>
-#include <openssl/dh.h>
-#include <openssl/x509.h>
-#include <openssl/pkcs7.h>
-#include <openssl/pkcs12.h>
-#include <openssl/obj_mac.h>
-#include <openssl/x509v3.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/sha.h>
-#include <openssl/asn1.h>
-#include <openssl/pem.h>
-#include <openssl/asn1t.h>
-#include <openssl/cms.h>
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
-#include <openssl/core_names.h>
-#include <openssl/decoder.h>
-#endif
-
-#define DN_BUF_LEN 256
-#define MAX_CREDS_ALLOWED 20
-
-struct _pkinit_cred_info {
- char *name;
- X509 *cert;
- EVP_PKEY *key;
-#ifndef WITHOUT_PKCS11
- CK_BYTE_PTR cert_id;
- int cert_id_len;
-#endif
-};
-typedef struct _pkinit_cred_info * pkinit_cred_info;
-
-struct _pkinit_identity_crypto_context {
- pkinit_cred_info creds[MAX_CREDS_ALLOWED+1];
- STACK_OF(X509) *my_certs; /* available user certs */
- char *identity; /* identity name for user cert */
- int cert_index; /* cert to use out of available certs*/
- EVP_PKEY *my_key; /* available user keys if in filesystem */
- STACK_OF(X509) *trustedCAs; /* available trusted ca certs */
- STACK_OF(X509) *intermediateCAs; /* available intermediate ca certs */
- STACK_OF(X509_CRL) *revoked; /* available crls */
- int pkcs11_method;
- krb5_prompter_fct prompter;
- void *prompter_data;
-#ifndef WITHOUT_PKCS11
- char *p11_module_name;
- CK_SLOT_ID slotid;
- char *token_label;
- char *cert_label;
- /* These are crypto-specific */
- struct plugin_file_handle *p11_module;
- CK_SESSION_HANDLE session;
- CK_FUNCTION_LIST_PTR p11;
- uint8_t *cert_id;
- size_t cert_id_len;
- CK_MECHANISM_TYPE mech;
-#endif
- krb5_boolean defer_id_prompt;
- pkinit_deferred_id *deferred_ids;
-};
-
-struct _pkinit_plg_crypto_context {
- EVP_PKEY *dh_1024;
- EVP_PKEY *dh_2048;
- EVP_PKEY *dh_4096;
- EVP_PKEY *ec_p256;
- EVP_PKEY *ec_p384;
- EVP_PKEY *ec_p521;
- ASN1_OBJECT *id_pkinit_authData;
- ASN1_OBJECT *id_pkinit_DHKeyData;
- ASN1_OBJECT *id_pkinit_rkeyData;
- ASN1_OBJECT *id_pkinit_san;
- ASN1_OBJECT *id_ms_san_upn;
- ASN1_OBJECT *id_pkinit_KPClientAuth;
- ASN1_OBJECT *id_pkinit_KPKdc;
- ASN1_OBJECT *id_ms_kp_sc_logon;
- ASN1_OBJECT *id_kp_serverAuth;
-};
-
-struct _pkinit_req_crypto_context {
- X509 *received_cert;
- EVP_PKEY *client_pkey;
-};
-
-#endif /* _PKINIT_CRYPTO_OPENSSL_H */
--
2.47.1

View file

@ -1,157 +0,0 @@
From 1b01057df4c2223fbf92be44f1e764207208ef03 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 26 Feb 2024 19:03:38 -0500
Subject: [PATCH] Use SoftHSMv2 for PKCS11 PKINIT tests
Instead of softpkcs11, use SoftHSMv2 to mock the PKCS11 token for
PKINIT tests. Use pkcs11-tool from OpenSC to initialize the token and
import a certificate and key. SoftHSM does not support PIN-less
tokens (see https://github.com/opendnssec/SoftHSMv2/issues/480) so
remove that test for now.
(cherry picked from commit 8ab61608236883fdc5c2d43f4bd1ff2094401d19)
---
.github/workflows/build.yml | 2 +-
src/tests/t_pkinit.py | 82 ++++++++++++++++++++-----------------
2 files changed, 45 insertions(+), 39 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 68a4788adb..d7ae86b150 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -33,7 +33,7 @@ jobs:
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update -qq
- sudo apt-get install -y bison gettext keyutils ldap-utils libcmocka-dev libldap2-dev libkeyutils-dev libsasl2-dev libssl-dev python3-kdcproxy python3-pip slapd tcsh
+ sudo apt-get install -y bison gettext keyutils ldap-utils libcmocka-dev libldap2-dev libkeyutils-dev libsasl2-dev libssl-dev python3-kdcproxy python3-pip slapd tcsh softhsm2 opensc
pip3 install pyrad
- name: Build
env:
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
index f8f2debc1b..4435746429 100755
--- a/src/tests/t_pkinit.py
+++ b/src/tests/t_pkinit.py
@@ -1,11 +1,10 @@
from k5test import *
+import re
# Skip this test if pkinit wasn't built.
if not pkinit_enabled:
skip_rest('PKINIT tests', 'PKINIT module not built')
-soft_pkcs11 = os.path.join(buildtop, 'tests', 'softpkcs11', 'softpkcs11.so')
-
# Construct a krb5.conf fragment configuring pkinit.
user_pem = os.path.join(pkinit_certs, 'user.pem')
privkey_pem = os.path.join(pkinit_certs, 'privkey.pem')
@@ -55,9 +54,6 @@ p12_upn2_identity = 'PKCS12:%s' % user_upn2_p12
p12_upn3_identity = 'PKCS12:%s' % user_upn3_p12
p12_generic_identity = 'PKCS12:%s' % generic_p12
p12_enc_identity = 'PKCS12:%s' % user_enc_p12
-p11_identity = 'PKCS11:' + soft_pkcs11
-p11_token_identity = ('PKCS11:module_name=' + soft_pkcs11 +
- ':slotid=1:token=SoftToken (token)')
# Start a realm with the test kdb module for the following UPN SAN tests.
realm = K5Realm(kdc_conf=alias_kdc_conf, create_kdb=False, pkinit=True)
@@ -389,53 +385,63 @@ realm.klist(realm.user_princ)
realm.kinit(realm.user_princ, flags=['-X', 'X509_user_identity=,'],
expected_code=1, expected_msg='Preauthentication failed while')
-softpkcs11rc = os.path.join(os.getcwd(), 'testdir', 'soft-pkcs11.rc')
-realm.env['SOFTPKCS11RC'] = softpkcs11rc
+softhsm2 = '/usr/lib/softhsm/libsofthsm2.so'
+if not os.path.exists(softhsm2):
+ skip_rest('PKCS11 tests', 'SoftHSMv2 required')
+pkcs11_tool = which('pkcs11-tool')
+if not pkcs11_tool:
+ skip_rest('PKCS11 tests', 'pkcs11-tool from OpenSC required')
+tool_cmd = [pkcs11_tool, '--module', softhsm2]
+
+# Prepare a SoftHSM token.
+softhsm2_conf = os.path.join(realm.testdir, 'softhsm2.conf')
+softhsm2_tokens = os.path.join(realm.testdir, 'tokens')
+os.mkdir(softhsm2_tokens)
+realm.env['SOFTHSM2_CONF'] = softhsm2_conf
+with open(softhsm2_conf, 'w') as f:
+ f.write('directories.tokendir = %s\n' % softhsm2_tokens)
+realm.run(tool_cmd + ['--init-token', '--label', 'user',
+ '--so-pin', 'sopin', '--init-pin', '--pin', 'userpin'])
+realm.run(tool_cmd + ['-w', user_pem, '-y', 'cert'])
+realm.run(tool_cmd + ['-w', privkey_pem, '-y', 'privkey',
+ '-l', '--pin', 'userpin'])
+
+# Extract the slot ID generated by SoftHSM.
+out = realm.run(tool_cmd + ['-L'])
+m = re.search(r'slot ID 0x([0-9a-f]+)\n', out)
+if not m:
+ fail('could not extract slot ID from SoftHSM token')
+slot_id = int(m.group(1), 16)
+
+p11_attr = 'X509_user_identity=PKCS11:' + softhsm2
+p11_token_identity = ('PKCS11:module_name=%s:slotid=%d:token=user' %
+ (softhsm2, slot_id))
-# PKINIT with PKCS11: identity, with no need for a PIN.
-mark('PKCS11 identity, no PIN')
-conf = open(softpkcs11rc, 'w')
-conf.write("%s\t%s\t%s\t%s\n" % ('user', 'user token', user_pem, privkey_pem))
-conf.close()
-# Expect to succeed without having to supply any more information.
-realm.kinit(realm.user_princ,
- flags=['-X', 'X509_user_identity=%s' % p11_identity])
+mark('PKCS11 identity, with PIN (prompter)')
+realm.kinit(realm.user_princ, flags=['-X', p11_attr], password='userpin')
realm.klist(realm.user_princ)
realm.run([kvno, realm.host_princ])
-# PKINIT with PKCS11: identity, with a PIN supplied by the prompter.
-mark('PKCS11 identity, with PIN (prompter)')
-os.remove(softpkcs11rc)
-conf = open(softpkcs11rc, 'w')
-conf.write("%s\t%s\t%s\t%s\n" % ('user', 'user token', user_pem,
- privkey_enc_pem))
-conf.close()
-# Expect failure if the responder does nothing, and there's no prompter
+mark('PKCS11 identity, unavailable PIN')
realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % p11_token_identity,
- '-X', 'X509_user_identity=%s' % p11_identity, realm.user_princ],
- expected_code=2)
-realm.kinit(realm.user_princ,
- flags=['-X', 'X509_user_identity=%s' % p11_identity],
- password='encrypted')
-realm.klist(realm.user_princ)
-realm.run([kvno, realm.host_princ])
+ '-X', p11_attr, realm.user_princ], expected_code=2)
-# Supply the wrong PIN.
mark('PKCS11 identity, wrong PIN')
expected_trace = ('PKINIT client has no configured identity; giving up',)
realm.kinit(realm.user_princ,
- flags=['-X', 'X509_user_identity=%s' % p11_identity],
+ flags=['-X', p11_attr],
password='wrong', expected_code=1, expected_trace=expected_trace)
# PKINIT with PKCS11: identity, with a PIN supplied by the responder.
-# Supply the response in raw form.
+# Supply the response in raw form. Expect the PIN_COUNT_LOW flag (1)
+# to be set due to the previous test.
mark('PKCS11 identity, with PIN (responder)')
-realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % p11_token_identity,
- '-r', 'pkinit={"%s": "encrypted"}' % p11_token_identity,
- '-X', 'X509_user_identity=%s' % p11_identity, realm.user_princ])
+realm.run(['./responder', '-x', 'pkinit={"%s": 1}' % p11_token_identity,
+ '-r', 'pkinit={"%s": "userpin"}' % p11_token_identity,
+ '-X', p11_attr, realm.user_princ])
# Supply the response through the convenience API.
-realm.run(['./responder', '-X', 'X509_user_identity=%s' % p11_identity,
- '-p', '%s=%s' % (p11_token_identity, 'encrypted'),
+realm.run(['./responder', '-X', p11_attr,
+ '-p', '%s=%s' % (p11_token_identity, 'userpin'),
realm.user_princ])
realm.klist(realm.user_princ)
realm.run([kvno, realm.host_princ])
--
2.47.1

View file

@ -1,202 +0,0 @@
From b0315d30f066c4241fcecc33dd9e4d1c7c28b9d8 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 9 Feb 2024 17:32:40 -0500
Subject: [PATCH] Simplify PKINIT cert representation
In the _pkinit_identity_crypto_context structure, the my_certs field
is a stack which only ever contains one cert and is only ever used to
retrieve that one cert. The cert_index field is always 0. Replace
these fields with a my_cert field pointing directly to the X509
certificate.
Simplify crypto_cert_select_default() by making it call
crypto_cert_select() with index 0 after verifying the certificate
count.
(cherry picked from commit f95dfb7908456f9563cee66706216a21df8d791f)
---
.../preauth/pkinit/pkinit_crypto_openssl.c | 74 +++++--------------
1 file changed, 20 insertions(+), 54 deletions(-)
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index ae8599d5a2..da59cb1e02 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -73,10 +73,9 @@ typedef struct _pkinit_cred_info *pkinit_cred_info;
struct _pkinit_identity_crypto_context {
pkinit_cred_info creds[MAX_CREDS_ALLOWED+1];
- STACK_OF(X509) *my_certs; /* available user certs */
+ X509 *my_cert; /* selected user or KDC cert */
char *identity; /* identity name for user cert */
- int cert_index; /* cert to use out of available certs*/
- EVP_PKEY *my_key; /* available user keys if in filesystem */
+ EVP_PKEY *my_key; /* selected cert key if in filesystem */
STACK_OF(X509) *trustedCAs; /* available trusted ca certs */
STACK_OF(X509) *intermediateCAs; /* available intermediate ca certs */
STACK_OF(X509_CRL) *revoked; /* available crls */
@@ -1489,8 +1488,7 @@ pkinit_init_certs(pkinit_identity_crypto_context ctx)
for (i = 0; i < MAX_CREDS_ALLOWED; i++)
ctx->creds[i] = NULL;
- ctx->my_certs = NULL;
- ctx->cert_index = 0;
+ ctx->my_cert = NULL;
ctx->my_key = NULL;
ctx->trustedCAs = NULL;
ctx->intermediateCAs = NULL;
@@ -1506,8 +1504,8 @@ pkinit_fini_certs(pkinit_identity_crypto_context ctx)
if (ctx == NULL)
return;
- if (ctx->my_certs != NULL)
- sk_X509_pop_free(ctx->my_certs, X509_free);
+ if (ctx->my_cert != NULL)
+ X509_free(ctx->my_cert);
if (ctx->my_key != NULL)
EVP_PKEY_free(ctx->my_key);
@@ -1696,7 +1694,6 @@ cms_signeddata_create(krb5_context context,
ASN1_OCTET_STRING *digest = NULL;
unsigned int alg_len = 0, digest_len = 0;
unsigned char *y = NULL;
- X509 *cert = NULL;
ASN1_OBJECT *oid = NULL, *oid_copy;
/* Start creating PKCS7 data. */
@@ -1715,7 +1712,7 @@ cms_signeddata_create(krb5_context context,
if (oid == NULL)
goto cleanup;
- if (id_cryptoctx->my_certs != NULL) {
+ if (id_cryptoctx->my_cert != NULL) {
X509_STORE *certstore = NULL;
X509_STORE_CTX *certctx;
STACK_OF(X509) *certstack = NULL;
@@ -1726,8 +1723,6 @@ cms_signeddata_create(krb5_context context,
if ((cert_stack = sk_X509_new_null()) == NULL)
goto cleanup;
- cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
-
certstore = X509_STORE_new();
if (certstore == NULL)
goto cleanup;
@@ -1736,7 +1731,7 @@ cms_signeddata_create(krb5_context context,
certctx = X509_STORE_CTX_new();
if (certctx == NULL)
goto cleanup;
- X509_STORE_CTX_init(certctx, certstore, cert,
+ X509_STORE_CTX_init(certctx, certstore, id_cryptoctx->my_cert,
id_cryptoctx->intermediateCAs);
X509_STORE_CTX_trusted_stack(certctx, id_cryptoctx->trustedCAs);
if (!X509_verify_cert(certctx)) {
@@ -1764,13 +1759,13 @@ cms_signeddata_create(krb5_context context,
if (!ASN1_INTEGER_set(p7si->version, 1))
goto cleanup;
if (!X509_NAME_set(&p7si->issuer_and_serial->issuer,
- X509_get_issuer_name(cert)))
+ X509_get_issuer_name(id_cryptoctx->my_cert)))
goto cleanup;
/* because ASN1_INTEGER_set is used to set a 'long' we will do
* things the ugly way. */
ASN1_INTEGER_free(p7si->issuer_and_serial->serial);
if (!(p7si->issuer_and_serial->serial =
- ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
+ ASN1_INTEGER_dup(X509_get_serialNumber(id_cryptoctx->my_cert))))
goto cleanup;
/* will not fill-out EVP_PKEY because it's on the smartcard */
@@ -3311,7 +3306,7 @@ pkinit_check_kdc_pkid(krb5_context context,
PKCS7_ISSUER_AND_SERIAL *is = NULL;
const unsigned char *p = pdid_buf;
int status = 1;
- X509 *kdc_cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
+ X509 *kdc_cert = id_cryptoctx->my_cert;
*valid_kdcPkId = 0;
pkiDebug("found kdcPkId in AS REQ\n");
@@ -4783,7 +4778,8 @@ cleanup:
}
/*
- * Set the certificate in idctx->creds[cred_index] as the selected certificate.
+ * Set the certificate in idctx->creds[cred_index] as the selected certificate,
+ * stealing pointers from it.
*/
krb5_error_code
crypto_cert_select(krb5_context context, pkinit_identity_crypto_context idctx,
@@ -4795,20 +4791,17 @@ crypto_cert_select(krb5_context context, pkinit_identity_crypto_context idctx,
return ENOENT;
ci = idctx->creds[cred_index];
- /* copy the selected cert into our id_cryptoctx */
- if (idctx->my_certs != NULL)
- sk_X509_pop_free(idctx->my_certs, X509_free);
- idctx->my_certs = sk_X509_new_null();
- sk_X509_push(idctx->my_certs, ci->cert);
- free(idctx->identity);
+
+ idctx->my_cert = ci->cert;
+ ci->cert = NULL;
+
/* hang on to the selected credential name */
+ free(idctx->identity);
if (ci->name != NULL)
idctx->identity = strdup(ci->name);
else
idctx->identity = NULL;
- ci->cert = NULL; /* Don't free it twice */
- idctx->cert_index = 0;
if (idctx->pkcs11_method != 1) {
idctx->my_key = ci->key;
ci->key = NULL; /* Don't free it twice */
@@ -4837,41 +4830,14 @@ crypto_cert_select_default(krb5_context context,
retval = crypto_cert_get_count(id_cryptoctx, &cert_count);
if (retval)
- goto errout;
+ return retval;
if (cert_count != 1) {
TRACE_PKINIT_NO_DEFAULT_CERT(context, cert_count);
- retval = EINVAL;
- goto errout;
- }
- /* copy the selected cert into our id_cryptoctx */
- if (id_cryptoctx->my_certs != NULL) {
- sk_X509_pop_free(id_cryptoctx->my_certs, X509_free);
+ return EINVAL;
}
- id_cryptoctx->my_certs = sk_X509_new_null();
- sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
- id_cryptoctx->creds[0]->cert = NULL; /* Don't free it twice */
- id_cryptoctx->cert_index = 0;
- /* hang on to the selected credential name */
- if (id_cryptoctx->creds[0]->name != NULL)
- id_cryptoctx->identity = strdup(id_cryptoctx->creds[0]->name);
- else
- id_cryptoctx->identity = NULL;
- if (id_cryptoctx->pkcs11_method != 1) {
- id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
- id_cryptoctx->creds[0]->key = NULL; /* Don't free it twice */
- }
-#ifndef WITHOUT_PKCS11
- else {
- id_cryptoctx->cert_id = id_cryptoctx->creds[0]->cert_id;
- id_cryptoctx->creds[0]->cert_id = NULL; /* Don't free it twice */
- id_cryptoctx->cert_id_len = id_cryptoctx->creds[0]->cert_id_len;
- }
-#endif
- retval = 0;
-errout:
- return retval;
+ return crypto_cert_select(context, id_cryptoctx, 0);
}
--
2.47.1

File diff suppressed because it is too large Load diff

View file

@ -1,599 +0,0 @@
From e43c05e7b0b93401dd68fc3ec3186c3a455b04ea Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 23 Feb 2024 13:51:26 -0500
Subject: [PATCH] Improve PKCS11 error reporting in PKINIT
Create a helper p11err() to set extended error message for failed
PKCS11 operations, and use it instead of pkiDebug() and pkcs11error().
ticket: 9113 (new)
(cherry picked from commit 98afb314d13939cbee19c69885dcb655db8460da)
---
.../preauth/pkinit/pkinit_crypto_openssl.c | 262 ++++++++++--------
src/plugins/preauth/pkinit/pkinit_trace.h | 9 -
2 files changed, 142 insertions(+), 129 deletions(-)
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 4accfc2664..402bf1b9b3 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -161,9 +161,11 @@ static krb5_error_code pkinit_create_sequence_of_principal_identifiers
int type, krb5_pa_data ***e_data_out);
#ifndef WITHOUT_PKCS11
-static krb5_error_code pkinit_find_private_key
-(pkinit_identity_crypto_context, CK_ATTRIBUTE_TYPE usage,
- CK_OBJECT_HANDLE *objp);
+static krb5_error_code
+pkinit_find_private_key(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx,
+ CK_ATTRIBUTE_TYPE usage,
+ CK_OBJECT_HANDLE *objp);
static krb5_error_code pkinit_login
(krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
CK_TOKEN_INFO *tip, const char *password);
@@ -180,6 +182,8 @@ 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);
+
+static krb5_error_code p11err(krb5_context context, CK_RV rv, const char *op);
#endif /* WITHOUT_PKCS11 */
static krb5_error_code pkinit_sign_data_fs
@@ -197,9 +201,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 const char *
-pkcs11err(int err);
-
#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -944,8 +945,9 @@ cleanup:
#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+#ifndef WITHOUT_PKC11
static struct pkcs11_errstrings {
- short code;
+ CK_RV code;
char *text;
} pkcs11_errstrings[] = {
{ 0x0, "ok" },
@@ -1035,6 +1037,7 @@ static struct pkcs11_errstrings {
{ 0x200, "function rejected" },
{ -1, NULL }
};
+#endif
MAKE_INIT_FUNCTION(pkinit_openssl_init);
@@ -1563,6 +1566,8 @@ pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
free(ctx->token_label);
free(ctx->cert_id);
free(ctx->cert_label);
+ ctx->p11_module_name = ctx->token_label = ctx->cert_label = NULL;
+ ctx->cert_id = NULL;
#endif
}
@@ -3344,48 +3349,53 @@ pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
}
#ifndef WITHOUT_PKCS11
-static struct plugin_file_handle *
+static krb5_error_code
load_pkcs11_module(krb5_context context, const char *modname,
- CK_FUNCTION_LIST_PTR_PTR p11p)
+ struct plugin_file_handle **handle_out,
+ CK_FUNCTION_LIST_PTR_PTR p11_out)
{
struct plugin_file_handle *handle = NULL;
- CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
+ CK_RV rv, (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
struct errinfo einfo = EMPTY_ERRINFO;
- const char *errmsg = NULL;
+ const char *errmsg = NULL, *failure;
void (*sym)(void);
long err;
- CK_RV rv;
TRACE_PKINIT_PKCS11_OPEN(context, modname);
err = krb5int_open_plugin(modname, &handle, &einfo);
if (err) {
- errmsg = k5_get_error(&einfo, err);
- TRACE_PKINIT_PKCS11_OPEN_FAILED(context, errmsg);
+ failure = _("Cannot load PKCS11 module");
goto error;
}
err = krb5int_get_plugin_func(handle, "C_GetFunctionList", &sym, &einfo);
if (err) {
- errmsg = k5_get_error(&einfo, err);
- TRACE_PKINIT_PKCS11_GETSYM_FAILED(context, errmsg);
+ failure = _("Cannot find C_GetFunctionList in PKCS11 module");
goto error;
}
getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))sym;
- rv = (*getflist)(p11p);
+ rv = (*getflist)(p11_out);
if (rv != CKR_OK) {
- TRACE_PKINIT_PKCS11_GETFLIST_FAILED(context, pkcs11err(rv));
+ failure = _("Cannot retrieve function list in PKCS11 module");
goto error;
}
- return handle;
+ *handle_out = handle;
+ return 0;
error:
- k5_free_error(&einfo, errmsg);
+ if (err) {
+ errmsg = k5_get_error(&einfo, err);
+ k5_setmsg(context, err, _("%s: %s"), failure, errmsg);
+ } else {
+ err = KRB5KDC_ERR_PREAUTH_FAILED;
+ k5_setmsg(context, err, "%s", failure);
+ }
k5_clear_error(&einfo);
if (handle != NULL)
krb5int_close_plugin(handle);
- return NULL;
+ return err;
}
static krb5_error_code
@@ -3393,12 +3403,13 @@ pkinit_login(krb5_context context,
pkinit_identity_crypto_context id_cryptoctx,
CK_TOKEN_INFO *tip, const char *password)
{
+ krb5_error_code ret = 0;
+ CK_RV rv;
krb5_data rdat;
char *prompt;
const char *warning;
krb5_prompt kprompt;
krb5_prompt_type prompt_type;
- int r = 0;
if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
rdat.data = NULL;
@@ -3407,7 +3418,7 @@ pkinit_login(krb5_context context,
rdat.data = strdup(password);
rdat.length = strlen(password);
} else if (id_cryptoctx->prompter == NULL) {
- r = KRB5_LIBOS_CANTREADPWD;
+ ret = KRB5_LIBOS_CANTREADPWD;
rdat.data = NULL;
} else {
if (tip->flags & CKF_USER_PIN_LOCKED)
@@ -3431,31 +3442,28 @@ pkinit_login(krb5_context context,
/* PROMPTER_INVOCATION */
k5int_set_prompt_types(context, &prompt_type);
- r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
- NULL, NULL, 1, &kprompt);
+ ret = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
+ NULL, NULL, 1, &kprompt);
k5int_set_prompt_types(context, 0);
free(prompt);
}
- if (r == 0) {
- r = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
- (u_char *) rdat.data, rdat.length);
-
- if (r != CKR_OK) {
- TRACE_PKINIT_PKCS11_LOGIN_FAILED(context, pkcs11err(r));
- r = KRB5KDC_ERR_PREAUTH_FAILED;
- }
+ if (!ret) {
+ rv = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
+ (uint8_t *)rdat.data, rdat.length);
+ if (rv != CKR_OK)
+ ret = p11err(context, rv, "C_Login");
}
free(rdat.data);
- return r;
+ return ret;
}
static krb5_error_code
pkinit_open_session(krb5_context context,
pkinit_identity_crypto_context cctx)
{
- CK_ULONG i, pret;
+ CK_ULONG i, rv;
unsigned char *cp;
size_t label_len;
CK_ULONG count = 0;
@@ -3469,30 +3477,35 @@ pkinit_open_session(krb5_context context,
return 0; /* session already open */
/* Load module */
- cctx->p11_module = load_pkcs11_module(context, cctx->p11_module_name,
- &cctx->p11);
- if (cctx->p11_module == NULL)
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ ret = load_pkcs11_module(context, cctx->p11_module_name, &cctx->p11_module,
+ &cctx->p11);
+ if (ret)
+ goto cleanup;
/* Init */
- pret = cctx->p11->C_Initialize(NULL);
- if (pret != CKR_OK) {
- pkiDebug("C_Initialize: %s\n", pkcs11err(pret));
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ rv = cctx->p11->C_Initialize(NULL);
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_Initialize");
+ goto cleanup;
}
/* Get the list of available slots */
- if (cctx->p11->C_GetSlotList(TRUE, NULL, &count) != CKR_OK)
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ rv = cctx->p11->C_GetSlotList(TRUE, NULL, &count);
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_GetSlotList");
+ goto cleanup;
+ }
if (count == 0) {
TRACE_PKINIT_PKCS11_NO_TOKEN(context);
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
}
- slotlist = calloc(count, sizeof(CK_SLOT_ID));
+ slotlist = k5calloc(count, sizeof(CK_SLOT_ID), &ret);
if (slotlist == NULL)
- return ENOMEM;
- if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ goto cleanup;
+ rv = cctx->p11->C_GetSlotList(TRUE, slotlist, &count);
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_GetSlotList");
goto cleanup;
}
@@ -3503,19 +3516,17 @@ pkinit_open_session(krb5_context context,
continue;
/* Open session */
- pret = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
- NULL, NULL, &cctx->session);
- if (pret != CKR_OK) {
- pkiDebug("C_OpenSession: %s\n", pkcs11err(pret));
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ rv = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
+ NULL, NULL, &cctx->session);
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_OpenSession");
goto cleanup;
}
/* Get token info */
- pret = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo);
- if (pret != CKR_OK) {
- pkiDebug("C_GetTokenInfo: %s\n", pkcs11err(pret));
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ rv = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo);
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_GetTokenInfo");
goto cleanup;
}
@@ -3577,6 +3588,10 @@ pkinit_open_session(krb5_context context,
ret = 0;
cleanup:
+ /* On error, finalize the PKCS11 fields to ensure that we don't mistakenly
+ * short-circuit with success on the next call. */
+ if (ret)
+ pkinit_fini_pkcs11(cctx);
free(slotlist);
free(p11name);
return ret;
@@ -3598,16 +3613,17 @@ cleanup:
* If there are more than one, we just take the first one.
*/
-krb5_error_code
-pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
+static krb5_error_code
+pkinit_find_private_key(krb5_context context,
+ pkinit_identity_crypto_context id_cryptoctx,
CK_ATTRIBUTE_TYPE usage,
CK_OBJECT_HANDLE *objp)
{
CK_OBJECT_CLASS cls;
CK_ATTRIBUTE attrs[4];
CK_ULONG count;
+ CK_RV rv;
unsigned int nattrs = 0;
- int r;
#ifdef PKINIT_USE_KEY_USAGE
CK_BBOOL true_false;
#endif
@@ -3637,18 +3653,21 @@ pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
nattrs++;
- r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
- if (r != CKR_OK) {
- pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
- pkcs11err(r));
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
+ rv = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs,
+ nattrs);
+ if (rv != CKR_OK)
+ return p11err(context, rv, _("C_FindObjectsInit"));
- r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
+ rv = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1,
+ &count);
id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
- pkiDebug("found %d private keys (%s)\n", (int)count, pkcs11err(r));
- if (r != CKR_OK || count < 1)
+ if (rv != CKR_OK)
+ return p11err(context, rv, _("C_FindObjects"));
+ if (count < 1) {
+ k5_setmsg(context, KRB5KDC_ERR_PREAUTH_FAILED,
+ _("Found no private keys in PKCS11 token"));
return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
return 0;
}
#endif
@@ -3796,34 +3815,32 @@ pkinit_sign_data_pkcs11(krb5_context context,
CK_FUNCTION_LIST_PTR p11;
CK_ATTRIBUTE attr;
CK_KEY_TYPE keytype;
+ CK_RV rv;
EVP_MD_CTX *ctx;
const EVP_MD *md = EVP_sha256();
unsigned int mdlen;
uint8_t mdbuf[EVP_MAX_MD_SIZE], *dinfo = NULL, *sigbuf = NULL, *input;
size_t dinfo_len, input_len;
- int r;
*sig = NULL;
*sig_len = 0;
- if (pkinit_open_session(context, id_cryptoctx)) {
- pkiDebug("can't open pkcs11 session\n");
- return KRB5KDC_ERR_PREAUTH_FAILED;
- }
+ ret = pkinit_open_session(context, id_cryptoctx);
+ if (ret)
+ return ret;
p11 = id_cryptoctx->p11;
session = id_cryptoctx->session;
- ret = pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
+ ret = pkinit_find_private_key(context, id_cryptoctx, CKA_SIGN, &obj);
if (ret)
return ret;
attr.type = CKA_KEY_TYPE;
attr.pValue = &keytype;
attr.ulValueLen = sizeof(keytype);
- r = p11->C_GetAttributeValue(session, obj, &attr, 1);
- if (r) {
- pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(r));
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ rv = p11->C_GetAttributeValue(session, obj, &attr, 1);
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_GetAttributeValue");
goto cleanup;
}
@@ -3865,10 +3882,9 @@ pkinit_sign_data_pkcs11(krb5_context context,
mech.pParameter = NULL;
mech.ulParameterLen = 0;
- r = p11->C_SignInit(session, &mech, obj);
- if (r != CKR_OK) {
- pkiDebug("C_SignInit: %s\n", pkcs11err(r));
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ rv = p11->C_SignInit(session, &mech, obj);
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_SignInit");
goto cleanup;
}
@@ -3881,18 +3897,17 @@ pkinit_sign_data_pkcs11(krb5_context context,
if (sigbuf == NULL)
goto cleanup;
- r = p11->C_Sign(session, input, input_len, sigbuf, &len);
- if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
+ rv = p11->C_Sign(session, input, input_len, sigbuf, &len);
+ if (rv == CKR_BUFFER_TOO_SMALL ||
+ (rv == CKR_OK && len >= PK_SIGLEN_GUESS)) {
free(sigbuf);
- pkiDebug("C_Sign realloc %d\n", (int) len);
sigbuf = k5alloc(len, &ret);
if (sigbuf == NULL)
goto cleanup;
- r = p11->C_Sign(session, input, input_len, sigbuf, &len);
+ rv = p11->C_Sign(session, input, input_len, sigbuf, &len);
}
- if (r != CKR_OK) {
- pkiDebug("C_Sign: %s\n", pkcs11err(r));
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_Sign");
goto cleanup;
}
@@ -4348,13 +4363,14 @@ reassemble_pkcs11_name(pkinit_identity_opts *idopts)
}
static krb5_error_code
-load_one_cert(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE session,
- pkinit_identity_opts *idopts, pkinit_cred_info *cred_out)
+load_one_cert(krb5_context context, CK_FUNCTION_LIST_PTR p11,
+ CK_SESSION_HANDLE session, pkinit_identity_opts *idopts,
+ pkinit_cred_info *cred_out)
{
krb5_error_code ret;
CK_ATTRIBUTE attrs[2];
CK_BYTE_PTR cert = NULL, cert_id = NULL;
- CK_RV pret;
+ CK_RV rv;
const unsigned char *cp;
CK_OBJECT_HANDLE obj;
CK_ULONG count;
@@ -4364,8 +4380,8 @@ load_one_cert(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE session,
*cred_out = NULL;
/* Look for X.509 cert. */
- pret = p11->C_FindObjects(session, &obj, 1, &count);
- if (pret != CKR_OK || count <= 0)
+ rv = p11->C_FindObjects(session, &obj, 1, &count);
+ if (rv != CKR_OK || count <= 0)
return 0;
/* Get cert and id len. */
@@ -4375,10 +4391,9 @@ load_one_cert(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE session,
attrs[1].type = CKA_ID;
attrs[1].pValue = NULL;
attrs[1].ulValueLen = 0;
- pret = p11->C_GetAttributeValue(session, obj, attrs, 2);
- if (pret != CKR_OK && pret != CKR_BUFFER_TOO_SMALL) {
- pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(pret));
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ rv = p11->C_GetAttributeValue(session, obj, attrs, 2);
+ if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL) {
+ ret = p11err(context, rv, "C_GetAttributeValue");
goto cleanup;
}
@@ -4393,10 +4408,9 @@ load_one_cert(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE session,
attrs[0].pValue = cert;
attrs[1].type = CKA_ID;
attrs[1].pValue = cert_id;
- pret = p11->C_GetAttributeValue(session, obj, attrs, 2);
- if (pret != CKR_OK) {
- pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(pret));
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ rv = p11->C_GetAttributeValue(session, obj, attrs, 2);
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_GetAttributeValue");
goto cleanup;
}
@@ -4406,7 +4420,8 @@ load_one_cert(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE session,
cp = (unsigned char *)cert;
x = d2i_X509(NULL, &cp, (int)attrs[0].ulValueLen);
if (x == NULL) {
- ret = KRB5KDC_ERR_PREAUTH_FAILED;
+ ret = oerr(context, 0,
+ _("Failed to decode X509 certificate from PKCS11 token"));
goto cleanup;
}
@@ -4444,7 +4459,7 @@ pkinit_get_certs_pkcs11(krb5_context context,
int i;
unsigned int nattrs;
krb5_error_code ret;
- CK_RV pret;
+ CK_RV rv;
/* Copy stuff from idopts -> id_cryptoctx */
if (idopts->p11_module_name != NULL) {
@@ -4516,16 +4531,16 @@ pkinit_get_certs_pkcs11(krb5_context context,
nattrs++;
}
- pret = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs,
- nattrs);
- if (pret != CKR_OK) {
- pkiDebug("C_FindObjectsInit: %s\n", pkcs11err(pret));
+ rv = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs,
+ nattrs);
+ if (rv != CKR_OK) {
+ ret = p11err(context, rv, "C_FindObjectsInit");
return KRB5KDC_ERR_PREAUTH_FAILED;
}
for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
- ret = load_one_cert(id_cryptoctx->p11, id_cryptoctx->session, idopts,
- &id_cryptoctx->creds[i]);
+ ret = load_one_cert(context, id_cryptoctx->p11, id_cryptoctx->session,
+ idopts, &id_cryptoctx->creds[i]);
if (ret)
return ret;
if (id_cryptoctx->creds[i] == NULL)
@@ -5510,19 +5525,26 @@ print_pubkey(BIGNUM * key, char *msg)
}
#endif
-static const char *
-pkcs11err(int err)
+#ifndef WITHOUT_PKCS11
+static krb5_error_code
+p11err(krb5_context context, CK_RV rv, const char *op)
{
+ krb5_error_code code = KRB5KDC_ERR_PREAUTH_FAILED;
int i;
+ const char *msg;
- for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
- if (pkcs11_errstrings[i].code == err)
+ for (i = 0; pkcs11_errstrings[i].text != NULL; i++) {
+ if (pkcs11_errstrings[i].code == rv)
break;
- if (pkcs11_errstrings[i].text != NULL)
- return (pkcs11_errstrings[i].text);
+ }
+ msg = pkcs11_errstrings[i].text;
+ if (msg == NULL)
+ msg = "unknown PKCS11 error";
- return "unknown PKCS11 error";
+ krb5_set_error_message(context, code, _("PKCS11 error (%s): %s"), op, msg);
+ return code;
}
+#endif
/*
* Add an item to the pkinit_identity_crypto_context's list of deferred
diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
index 1c1ceb5a41..1faa6816d7 100644
--- a/src/plugins/preauth/pkinit/pkinit_trace.h
+++ b/src/plugins/preauth/pkinit/pkinit_trace.h
@@ -98,21 +98,12 @@
#define TRACE_PKINIT_OPENSSL_ERROR(c, msg) \
TRACE(c, "PKINIT OpenSSL error: {str}", msg)
-#define TRACE_PKINIT_PKCS11_GETFLIST_FAILED(c, errstr) \
- TRACE(c, "PKINIT PKCS11 C_GetFunctionList failed: {str}", errstr)
-#define TRACE_PKINIT_PKCS11_GETSYM_FAILED(c, errstr) \
- TRACE(c, "PKINIT unable to find PKCS11 plugin symbol " \
- "C_GetFunctionList: {str}", errstr)
-#define TRACE_PKINIT_PKCS11_LOGIN_FAILED(c, errstr) \
- TRACE(c, "PKINIT PKCS11 C_Login failed: {str}", errstr)
#define TRACE_PKINIT_PKCS11_NO_MATCH_TOKEN(c) \
TRACE(c, "PKINIT PKCS#11 module has no matching tokens")
#define TRACE_PKINIT_PKCS11_NO_TOKEN(c) \
TRACE(c, "PKINIT PKCS#11 module shows no slots with tokens")
#define TRACE_PKINIT_PKCS11_OPEN(c, name) \
TRACE(c, "PKINIT opening PKCS#11 module \"{str}\"", name)
-#define TRACE_PKINIT_PKCS11_OPEN_FAILED(c, errstr) \
- TRACE(c, "PKINIT PKCS#11 module open failed: {str}", errstr)
#define TRACE_PKINIT_PKCS11_SLOT(c, slot, len, label) \
TRACE(c, "PKINIT PKCS#11 slotid {int} token {lenstr}", \
slot, len, label)
--
2.47.1

View file

@ -1,61 +0,0 @@
From 946f7dba8cea3d2ed0e68c5e7594cbd7e1364609 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 1 Aug 2024 10:56:07 +0200
Subject: [PATCH] Set missing mask flags for kdb5_util operations
Set KADM5_TL_DATA for the use_mkey and update_princ_encryption
commands. (Commit c877f13c8985d820583b0d7ac1bb4c5dc36e677e did this
for the add_new_mkey and purge_mkeys commands.) Set appropriate flags
for the add_random_key command.
[ghudson@mit.edu: combined two commits; pruned out proposed mask flag
additions for values represented within key data or tl-data (like
KADM5_MKVNO), as those flags are currently only used in the kadm5
protocol, not to communicate with the KDB module]
ticket: 9158 (new)
(cherry picked from commit 4ed7da378940198cf4415f86d4eb013de6ac6455)
---
src/kadmin/dbutil/kdb5_mkey.c | 4 +++-
src/kadmin/dbutil/kdb5_util.c | 3 +++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/kadmin/dbutil/kdb5_mkey.c b/src/kadmin/dbutil/kdb5_mkey.c
index aceb0a9b80..ac5c51d05e 100644
--- a/src/kadmin/dbutil/kdb5_mkey.c
+++ b/src/kadmin/dbutil/kdb5_mkey.c
@@ -525,6 +525,8 @@ kdb5_use_mkey(int argc, char *argv[])
goto cleanup_return;
}
+ master_entry->mask |= KADM5_TL_DATA;
+
if ((retval = krb5_db_put_principal(util_context, master_entry))) {
com_err(progname, retval,
_("while adding master key entry to the database"));
@@ -814,7 +816,7 @@ update_princ_encryption_1(void *cb, krb5_db_entry *ent)
goto fail;
}
- ent->mask |= KADM5_KEY_DATA;
+ ent->mask |= KADM5_KEY_DATA | KADM5_TL_DATA;
if ((retval = krb5_db_put_principal(util_context, ent))) {
com_err(progname, retval, _("while updating principal '%s' key data "
diff --git a/src/kadmin/dbutil/kdb5_util.c b/src/kadmin/dbutil/kdb5_util.c
index 55d529fa4c..afc817891b 100644
--- a/src/kadmin/dbutil/kdb5_util.c
+++ b/src/kadmin/dbutil/kdb5_util.c
@@ -600,6 +600,9 @@ add_random_key(int argc, char **argv)
exit_status++;
return;
}
+
+ dbent->mask |= KADM5_ATTRIBUTES | KADM5_KEY_DATA | KADM5_TL_DATA;
+
ret = krb5_db_put_principal(util_context, dbent);
krb5_db_free_principal(util_context, dbent);
if (ret) {
--
2.47.1

View file

@ -1,64 +0,0 @@
From 9b669dd42b28e7900f5ccac2816204e7d04ea23c Mon Sep 17 00:00:00 2001
From: Zoltan Borbely <Zoltan.Borbely@morganstanley.com>
Date: Tue, 28 Jan 2025 16:39:25 -0500
Subject: [PATCH] Prevent overflow when calculating ulog block size
In kdb_log.c:resize(), log an error and fail if the update size is
larger than the largest possible block size (2^16-1).
CVE-2025-24528:
In MIT krb5 release 1.7 and later with incremental propagation
enabled, an authenticated attacker can cause kadmind to write beyond
the end of the mapped region for the iprop log file, likely causing a
process crash.
[ghudson@mit.edu: edited commit message and added CVE description]
ticket: 9159 (new)
tags: pullup
target_version: 1.21-next
(cherry picked from commit 78ceba024b64d49612375be4a12d1c066b0bfbd0)
---
src/lib/kdb/kdb_log.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/lib/kdb/kdb_log.c b/src/lib/kdb/kdb_log.c
index e9b95fce59..c805ebd988 100644
--- a/src/lib/kdb/kdb_log.c
+++ b/src/lib/kdb/kdb_log.c
@@ -183,7 +183,7 @@ extend_file_to(int fd, unsigned int new_size)
*/
static krb5_error_code
resize(kdb_hlog_t *ulog, uint32_t ulogentries, int ulogfd,
- unsigned int recsize)
+ unsigned int recsize, const kdb_incr_update_t *upd)
{
unsigned int new_block, new_size;
@@ -195,6 +195,12 @@ resize(kdb_hlog_t *ulog, uint32_t ulogentries, int ulogfd,
new_block *= ULOG_BLOCK;
new_size += ulogentries * new_block;
+ if (new_block > UINT16_MAX) {
+ syslog(LOG_ERR, _("ulog overflow caused by principal %.*s"),
+ upd->kdb_princ_name.utf8str_t_len,
+ upd->kdb_princ_name.utf8str_t_val);
+ return KRB5_LOG_ERROR;
+ }
if (new_size > MAXLOGLEN)
return KRB5_LOG_ERROR;
@@ -291,7 +297,7 @@ store_update(kdb_log_context *log_ctx, kdb_incr_update_t *upd)
recsize = sizeof(kdb_ent_header_t) + upd_size;
if (recsize > ulog->kdb_block) {
- retval = resize(ulog, ulogentries, log_ctx->ulogfd, recsize);
+ retval = resize(ulog, ulogentries, log_ctx->ulogfd, recsize, upd);
if (retval)
return retval;
}
--
2.48.1

View file

@ -1,327 +0,0 @@
From c617915958a5cb05463713adcf03b6a0e0512ac3 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 16 Dec 2022 18:31:07 -0500
Subject: [PATCH] Don't issue session keys with deprecated enctypes
A paper by Tom Tervoort noted that rc4-hmac pre-hashes the input for
its checksum and GSS operations before applying HMAC, and is therefore
potentially vulnerable to hash collision attacks if a protocol
contains a restricted signing oracle.
In light of these potential attacks, begin the functional deprecation
of DES3 and RC4 by disallowing their use as session key enctypes by
default. Add the variables allow_des3 and allow_rc4 in case
negotiability of these enctypes for session keys needs to be turned
back on, with the expectation that in future releases the enctypes
will be more comprehensively deprecated.
ticket: 9081
(cherry picked from 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 | 5 +++--
src/tests/t_etype_info.py | 5 +++--
src/tests/t_sesskeynego.py | 28 +++++++++++++++++++++++++--
src/util/k5test.py | 9 ++++++++-
10 files changed, 116 insertions(+), 21 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index dca52e1426..d51fd3ce7e 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -95,6 +95,18 @@ 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 c4d5499d3b..2b4ed7da0b 100644
--- a/doc/admin/enctypes.rst
+++ b/doc/admin/enctypes.rst
@@ -48,12 +48,15 @@ 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.
+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.
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. See :ref:`set_string`
-in :ref:`kadmin(1)` for details.
+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.
Choosing enctypes for a service
@@ -87,6 +90,20 @@ 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 b7789a2dd8..d0a263aa7d 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -181,6 +181,8 @@ 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"
@@ -1241,6 +1243,8 @@ 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 93415ba862..c7b6e4090d 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -1108,6 +1108,16 @@ 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 1b420a3ac2..ea089f0fcc 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -1582,22 +1582,31 @@ 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 des3-cbc-sha1 was used for either the
- * reply key or the session key. */
+/* Display a warning via the prompter if a deprecated enctype was used for
+ * either the reply key or the session key. */
static void
-warn_des3(krb5_context context, krb5_init_creds_context ctx,
- krb5_enctype as_key_enctype)
+warn_deprecated(krb5_context context, krb5_init_creds_context ctx,
+ krb5_enctype as_key_enctype)
{
- const char *banner;
+ krb5_enctype etype;
+ char encbuf[128], banner[256];
- if (as_key_enctype != ENCTYPE_DES3_CBC_SHA1 &&
- ctx->cred.keyblock.enctype != ENCTYPE_DES3_CBC_SHA1)
- return;
if (ctx->prompter == NULL)
return;
- banner = _("Warning: encryption type des3-cbc-sha1 used for "
- "authentication is weak and will be disabled");
+ 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
+ return;
+
+ if (krb5_enctype_to_name(etype, FALSE, encbuf, sizeof(encbuf)) != 0)
+ return;
+ snprintf(banner, sizeof(banner),
+ _("Warning: encryption type %s used for authentication is "
+ "deprecated and will be disabled"), encbuf);
+
/* PROMPTER_INVOCATION */
(*ctx->prompter)(context, ctx->prompter_data, NULL, banner, 0, NULL);
}
@@ -1848,7 +1857,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_des3(context, ctx, encrypting_key.enctype);
+ warn_deprecated(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 582a2945ff..a32f8dbf03 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -220,6 +220,16 @@ 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 2f95d89967..e6bde47afc 100755
--- a/src/tests/gssapi/t_enctypes.py
+++ b/src/tests/gssapi/t_enctypes.py
@@ -10,8 +10,9 @@ 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 rc4-hmac:normal'
-conf = {'libdefaults': {'permitted_enctypes': 'aes rc4'},
+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'},
'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 a6f538b66d..75d9621dd6 100644
--- a/src/tests/t_etype_info.py
+++ b/src/tests/t_etype_info.py
@@ -1,7 +1,8 @@
from k5test import *
-supported_enctypes = 'aes128-cts rc4-hmac'
-conf = {'realms': {'$realm': {'supported_enctypes': supported_enctypes}}}
+supported_enctypes = 'aes128-cts des3-cbc-sha1 rc4-hmac'
+conf = {'libdefaults': {'allow_des3': 'true', 'allow_rc4': 'true'},
+ 'realms': {'$realm': {'supported_enctypes': supported_enctypes}}}
realm = K5Realm(create_host=False, get_creds=False, krb5_conf=conf)
realm.run([kadminl, 'addprinc', '-pw', 'pw', '+requires_preauth',
diff --git a/src/tests/t_sesskeynego.py b/src/tests/t_sesskeynego.py
index 9024aee838..5a213617b5 100755
--- a/src/tests/t_sesskeynego.py
+++ b/src/tests/t_sesskeynego.py
@@ -25,6 +25,8 @@ 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)
@@ -54,10 +56,12 @@ 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: Negotiate rc4-hmac session key when principal only has aes256 long-term.
+# 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.
realm.run([kadminl, 'setstr', 'server', 'session_enctypes',
'rc4-hmac,aes128-cts,aes256-cts'])
-test_kvno(realm, 'DEPRECATED:arcfour-hmac', 'aes256-cts-hmac-sha1-96')
+test_kvno(realm, 'aes128-cts-hmac-sha1-96', 'aes256-cts-hmac-sha1-96')
realm.stop()
# 4: Check that permitted_enctypes is a default for session key enctypes.
@@ -67,4 +71,24 @@ 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 d823653aa0..8e5f5ba8e9 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -1338,9 +1338,16 @@ _passes = [
# No special settings; exercises AES256.
('default', None, None, None),
+ # Exercise the DES3 enctype.
+ ('des3', None,
+ {'libdefaults': {'permitted_enctypes': 'des3 aes256-sha1'}},
+ {'realms': {'$realm': {
+ 'supported_enctypes': 'des3-cbc-sha1:normal',
+ 'master_key_type': 'des3-cbc-sha1'}}}),
+
# Exercise the arcfour enctype.
('arcfour', None,
- {'libdefaults': {'permitted_enctypes': 'rc4'}},
+ {'libdefaults': {'permitted_enctypes': 'rc4 aes256-sha1'}},
{'realms': {'$realm': {
'supported_enctypes': 'arcfour-hmac:normal',
'master_key_type': 'arcfour-hmac'}}}),
--
2.49.0

View file

@ -1,260 +0,0 @@
From b0993b57dbe584f9308cc7773b930efe76e19ba3 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Fri, 4 Apr 2025 15:08:36 +0200
Subject: [PATCH] [downstream] Remove 3des support (cumulative 1)
Remove mentions for the triple-DES encryption type which were added
since the previous downstream patch.
---
README | 15 +++++++--------
doc/admin/conf_files/krb5_conf.rst | 6 ------
doc/admin/enctypes.rst | 11 ++---------
doc/mitK5features.rst | 5 ++---
src/include/k5-int.h | 2 --
src/kdc/kdc_util.c | 2 --
src/lib/krb5/krb/init_ctx.c | 5 -----
src/man/krb5.conf.man | 6 ------
src/tests/gssapi/t_enctypes.py | 5 ++---
src/tests/t_etype_info.py | 4 ++--
src/tests/t_sesskeynego.py | 8 --------
src/util/k5test.py | 7 -------
12 files changed, 15 insertions(+), 61 deletions(-)
diff --git a/README b/README
index 6d6f7f16e3..9341bd3dd8 100644
--- a/README
+++ b/README
@@ -81,11 +81,11 @@ Triple-DES and RC4 transitions
------------------------------
Beginning with the krb5-1.21 release, the KDC will not issue tickets
-with triple-DES or RC4 session keys unless explicitly configured using
-the new allow_des3 and allow_rc4 variables in [libdefaults]. To
-facilitate the negotiation of session keys, the KDC will assume that
-all services can handle aes256-sha1 session keys unless the service
-principal has a session_enctypes string attribute.
+with RC4 session keys unless explicitly configured using the new
+allow_rc4 variable in [libdefaults]. To facilitate the negotiation of
+session keys, the KDC will assume that all services can handle
+aes256-sha1 session keys unless the service principal has a
+session_enctypes string attribute.
Beginning with the krb5-1.19 release, a warning will be issued if
initial credentials are acquired using the des3-cbc-sha1 encryption
@@ -164,9 +164,8 @@ Developer experience:
Protocol evolution:
-* The KDC will no longer issue tickets with RC4 or triple-DES session
- keys unless explicitly configured with the new allow_rc4 or
- allow_des3 variables respectively.
+* The KDC will no longer issue tickets with RC4 session keys unless
+ explicitly configured with the new allow_rc4 variable.
* The KDC will assume that all services can handle aes256-sha1 session
keys unless the service principal has a session_enctypes string
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index d51fd3ce7e..d20dcf18e3 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -95,12 +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
diff --git a/doc/admin/enctypes.rst b/doc/admin/enctypes.rst
index 2b4ed7da0b..6ce4638d5e 100644
--- a/doc/admin/enctypes.rst
+++ b/doc/admin/enctypes.rst
@@ -49,8 +49,8 @@ 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.
+aes256-cts-hmac-sha1-96; also, arcfour-hmac session keys will not be
+issued by default.
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
@@ -90,13 +90,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
diff --git a/doc/mitK5features.rst b/doc/mitK5features.rst
index cad0855724..64d746b0af 100644
--- a/doc/mitK5features.rst
+++ b/doc/mitK5features.rst
@@ -659,9 +659,8 @@ Release 1.21
* Protocol evolution:
- - The KDC will no longer issue tickets with RC4 or triple-DES
- session keys unless explicitly configured with the new allow_rc4
- or allow_des3 variables respectively.
+ - The KDC will no longer issue tickets with RC4 session keys unless
+ explicitly configured with the new allow_rc4 variable.
- The KDC will assume that all services can handle aes256-sha1
session keys unless the service principal has a session_enctypes
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index d0a263aa7d..82a763298d 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -181,7 +181,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"
@@ -1243,7 +1242,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;
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index c7b6e4090d..bafcf5f728 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -1113,8 +1113,6 @@ select_session_keytype(krb5_context context, krb5_db_entry *server,
* 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;
diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
index a32f8dbf03..82aba64c5e 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -220,11 +220,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;
diff --git a/src/man/krb5.conf.man b/src/man/krb5.conf.man
index 6c0e9aff8c..4b53988712 100644
--- a/src/man/krb5.conf.man
+++ b/src/man/krb5.conf.man
@@ -178,12 +178,6 @@ kdc.conf(5), but it is not a recommended practice.
The libdefaults section may contain any of the following relations:
.INDENT 0.0
.TP
-\fBallow_des3\fP
-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.)
-.TP
\fBallow_rc4\fP
Permit the KDC to issue tickets with arcfour\-hmac session keys.
In future releases, this flag will allow arcfour\-hmac to be used
diff --git a/src/tests/gssapi/t_enctypes.py b/src/tests/gssapi/t_enctypes.py
index e6bde47afc..1bb8c40b6b 100755
--- a/src/tests/gssapi/t_enctypes.py
+++ b/src/tests/gssapi/t_enctypes.py
@@ -10,9 +10,8 @@ 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'},
+supp='aes256-cts:normal aes128-cts:normal rc4-hmac:normal'
+conf = {'libdefaults': {'permitted_enctypes': 'aes rc4', 'allow_rc4': 'true'},
'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 75d9621dd6..e82ff7ff07 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'},
+supported_enctypes = 'aes128-cts rc4-hmac'
+conf = {'libdefaults': {'allow_rc4': '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..c7dba0ff5b 100755
--- a/src/tests/t_sesskeynego.py
+++ b/src/tests/t_sesskeynego.py
@@ -26,7 +26,6 @@ conf3 = {'libdefaults': {
'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)
@@ -78,13 +77,6 @@ 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'])
diff --git a/src/util/k5test.py b/src/util/k5test.py
index 8e5f5ba8e9..b953827018 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -1338,13 +1338,6 @@ _passes = [
# No special settings; exercises AES256.
('default', None, None, None),
- # Exercise the DES3 enctype.
- ('des3', None,
- {'libdefaults': {'permitted_enctypes': 'des3 aes256-sha1'}},
- {'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'}},
--
2.49.0

View file

@ -1,692 +0,0 @@
From 9d03713af124c2096d071ba36893018da8d71655 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Tue, 14 Jan 2025 13:31:11 +0100
Subject: [PATCH] Add PKINIT paChecksum2 from MS-PKCA v20230920
In 2023, Microsoft updated MS-PKCA to add the optional paChecksum2
element in the PKAuthenticator sequence. This checksum accepts SHA-1,
SHA-256, SHA-384, and SHA-512 digests.
In Windows Server 2025, this checksum becomes mandatory when using
PKINIT with FFDH (but strangely not with ECDH if SHA-1 is configured as
allowed).
[ghudson@mit.edu: refactored crypto interfaces to reduce complexity of
calling code]
ticket: 9166 (new)
(cherry picked from commit 310793ba63782af5ffa3a95d20e41f8f03ca7e00)
---
src/include/k5-int-pkinit.h | 25 ++--
src/lib/krb5/asn.1/asn1_k_encode.c | 18 ++-
src/plugins/preauth/pkinit/pkinit.h | 1 +
src/plugins/preauth/pkinit/pkinit_clnt.c | 41 +++----
src/plugins/preauth/pkinit/pkinit_constants.c | 42 +++++--
src/plugins/preauth/pkinit/pkinit_crypto.h | 24 +++-
.../preauth/pkinit/pkinit_crypto_openssl.c | 116 +++++++++++++++++-
src/plugins/preauth/pkinit/pkinit_kdf_test.c | 4 +-
src/plugins/preauth/pkinit/pkinit_lib.c | 16 ++-
src/plugins/preauth/pkinit/pkinit_srv.c | 38 ++----
src/plugins/preauth/pkinit/pkinit_trace.h | 5 +-
src/tests/asn.1/krb5_decode_test.c | 2 +-
src/tests/asn.1/ktest.c | 7 +-
src/tests/asn.1/ktest_equal.c | 2 +-
src/tests/asn.1/pkinit_encode.out | 2 +-
src/tests/asn.1/pkinit_trval.out | 2 +-
16 files changed, 250 insertions(+), 95 deletions(-)
diff --git a/src/include/k5-int-pkinit.h b/src/include/k5-int-pkinit.h
index 915904e518..cf6b1f99c5 100644
--- a/src/include/k5-int-pkinit.h
+++ b/src/include/k5-int-pkinit.h
@@ -36,21 +36,28 @@
* pkinit structures
*/
-/* PKAuthenticator */
-typedef struct _krb5_pk_authenticator {
- krb5_int32 cusec; /* (0..999999) */
- krb5_timestamp ctime;
- krb5_int32 nonce; /* (0..4294967295) */
- krb5_checksum paChecksum;
- krb5_data *freshnessToken;
-} krb5_pk_authenticator;
-
/* AlgorithmIdentifier */
typedef struct _krb5_algorithm_identifier {
krb5_data algorithm; /* OID */
krb5_data parameters; /* Optional */
} krb5_algorithm_identifier;
+/* PAChecksum2 */
+typedef struct _krb5_pachecksum2 {
+ krb5_data checksum;
+ krb5_algorithm_identifier algorithmIdentifier;
+} krb5_pachecksum2;
+
+/* PKAuthenticator */
+typedef struct _krb5_pk_authenticator {
+ krb5_int32 cusec; /* (0..999999) */
+ krb5_timestamp ctime;
+ krb5_int32 nonce; /* (0..4294967295) */
+ krb5_data paChecksum;
+ krb5_data *freshnessToken; /* Optional */
+ krb5_pachecksum2 *paChecksum2; /* Optional */
+} krb5_pk_authenticator;
+
/** AuthPack from RFC 4556*/
typedef struct _krb5_auth_pack {
krb5_pk_authenticator pkAuthenticator;
diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
index 5378b5c23b..cf7b500837 100644
--- a/src/lib/krb5/asn.1/asn1_k_encode.c
+++ b/src/lib/krb5/asn.1/asn1_k_encode.c
@@ -1394,20 +1394,30 @@ DEFSEQTYPE(pkinit_supp_pub_info, krb5_pkinit_supp_pub_info,
MAKE_ENCODER(encode_krb5_pkinit_supp_pub_info, pkinit_supp_pub_info);
MAKE_ENCODER(encode_krb5_sp80056a_other_info, sp80056a_other_info);
-/* A krb5_checksum encoded as an OCTET STRING, for PKAuthenticator. */
-DEFCOUNTEDTYPE(ostring_checksum, krb5_checksum, contents, length, octetstring);
+DEFFIELD(pachecksum2_0, krb5_pachecksum2, checksum, 0, ostring_data);
+DEFFIELD(pachecksum2_1, krb5_pachecksum2, algorithmIdentifier, 1,
+ algorithm_identifier);
+static const struct atype_info *pachecksum2_fields[] = {
+ &k5_atype_pachecksum2_0, &k5_atype_pachecksum2_1
+};
+DEFSEQTYPE(pachecksum2, krb5_pachecksum2, pachecksum2_fields);
+
+DEFPTRTYPE(pachecksum2_ptr, pachecksum2);
+DEFOPTIONALZEROTYPE(opt_pachecksum2_ptr, pachecksum2_ptr);
DEFFIELD(pk_authenticator_0, krb5_pk_authenticator, cusec, 0, int32);
DEFFIELD(pk_authenticator_1, krb5_pk_authenticator, ctime, 1, kerberos_time);
DEFFIELD(pk_authenticator_2, krb5_pk_authenticator, nonce, 2, int32);
DEFFIELD(pk_authenticator_3, krb5_pk_authenticator, paChecksum, 3,
- ostring_checksum);
+ ostring_data);
DEFFIELD(pk_authenticator_4, krb5_pk_authenticator, freshnessToken, 4,
opt_ostring_data_ptr);
+DEFFIELD(pk_authenticator_5, krb5_pk_authenticator, paChecksum2, 5,
+ opt_pachecksum2_ptr);
static const struct atype_info *pk_authenticator_fields[] = {
&k5_atype_pk_authenticator_0, &k5_atype_pk_authenticator_1,
&k5_atype_pk_authenticator_2, &k5_atype_pk_authenticator_3,
- &k5_atype_pk_authenticator_4
+ &k5_atype_pk_authenticator_4, &k5_atype_pk_authenticator_5
};
DEFSEQTYPE(pk_authenticator, krb5_pk_authenticator, pk_authenticator_fields);
diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
index 7ba7155bb4..a1564b6df2 100644
--- a/src/plugins/preauth/pkinit/pkinit.h
+++ b/src/plugins/preauth/pkinit/pkinit.h
@@ -338,6 +338,7 @@ void free_krb5_external_principal_identifier(krb5_external_principal_identifier
void free_krb5_algorithm_identifiers(krb5_algorithm_identifier ***in);
void free_krb5_algorithm_identifier(krb5_algorithm_identifier *in);
void free_krb5_kdc_dh_key_info(krb5_kdc_dh_key_info **in);
+void free_pachecksum2(krb5_context context, krb5_pachecksum2 **in);
krb5_error_code pkinit_copy_krb5_data(krb5_data *dst, const krb5_data *src);
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index b08022a214..433f477538 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -56,10 +56,9 @@ use_content_info(krb5_context context, pkinit_req_context req,
static krb5_error_code
pkinit_as_req_create(krb5_context context, pkinit_context plgctx,
pkinit_req_context reqctx, krb5_timestamp ctsec,
- krb5_int32 cusec, krb5_ui_4 nonce,
- const krb5_checksum *cksum,
- krb5_principal client, krb5_principal server,
- krb5_data **as_req);
+ krb5_int32 cusec, krb5_ui_4 nonce, const krb5_data *cksum,
+ const krb5_pachecksum2 *cksum2, krb5_principal client,
+ krb5_principal server, krb5_data **as_req);
static krb5_error_code
pkinit_as_rep_parse(krb5_context context, pkinit_context plgctx,
@@ -89,7 +88,8 @@ pa_pkinit_gen_req(krb5_context context,
krb5_timestamp ctsec = 0;
krb5_int32 cusec = 0;
krb5_ui_4 nonce = 0;
- krb5_checksum cksum;
+ krb5_data cksum = empty_data();
+ krb5_pachecksum2 *cksum2 = NULL;
krb5_data *der_req = NULL;
krb5_pa_data **return_pa_data = NULL;
@@ -118,15 +118,10 @@ pa_pkinit_gen_req(krb5_context context,
goto cleanup;
}
- retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,
- &cksum);
+ retval = crypto_generate_checksums(context, der_req, &cksum, &cksum2);
if (retval)
goto cleanup;
- TRACE_PKINIT_CLIENT_REQ_CHECKSUM(context, &cksum);
-#ifdef DEBUG_CKSUM
- pkiDebug("calculating checksum on buf size (%d)\n", der_req->length);
- print_buffer(der_req->data, der_req->length);
-#endif
+ TRACE_PKINIT_CLIENT_REQ_CHECKSUMS(context, &cksum, cksum2);
retval = cb->get_preauth_time(context, rock, TRUE, &ctsec, &cusec);
if (retval)
@@ -140,7 +135,8 @@ pa_pkinit_gen_req(krb5_context context,
nonce = request->nonce;
retval = pkinit_as_req_create(context, plgctx, reqctx, ctsec, cusec,
- nonce, &cksum, request->client, request->server, &out_data);
+ nonce, &cksum, cksum2, request->client,
+ request->server, &out_data);
if (retval) {
pkiDebug("error %d on pkinit_as_req_create; aborting PKINIT\n",
(int) retval);
@@ -168,23 +164,19 @@ pa_pkinit_gen_req(krb5_context context,
cleanup:
krb5_free_data(context, der_req);
- krb5_free_checksum_contents(context, &cksum);
+ krb5_free_data_contents(context, &cksum);
+ free_pachecksum2(context, &cksum2);
krb5_free_data(context, out_data);
krb5_free_pa_data(context, return_pa_data);
return retval;
}
static krb5_error_code
-pkinit_as_req_create(krb5_context context,
- pkinit_context plgctx,
- pkinit_req_context reqctx,
- krb5_timestamp ctsec,
- krb5_int32 cusec,
- krb5_ui_4 nonce,
- const krb5_checksum * cksum,
- krb5_principal client,
- krb5_principal server,
- krb5_data ** as_req)
+pkinit_as_req_create(krb5_context context, pkinit_context plgctx,
+ pkinit_req_context reqctx, krb5_timestamp ctsec,
+ krb5_int32 cusec, krb5_ui_4 nonce, const krb5_data *cksum,
+ const krb5_pachecksum2 *cksum2, krb5_principal client,
+ krb5_principal server, krb5_data **as_req)
{
krb5_error_code retval = ENOMEM;
krb5_data spki = empty_data(), *coded_auth_pack = NULL;
@@ -202,6 +194,7 @@ pkinit_as_req_create(krb5_context context,
auth_pack.pkAuthenticator.paChecksum = *cksum;
if (!reqctx->opts->disable_freshness)
auth_pack.pkAuthenticator.freshnessToken = reqctx->freshness_token;
+ auth_pack.pkAuthenticator.paChecksum2 = (krb5_pachecksum2 *)cksum2;
auth_pack.clientDHNonce.length = 0;
auth_pack.supportedKDFs = (krb5_data **)supported_kdf_alg_ids;
diff --git a/src/plugins/preauth/pkinit/pkinit_constants.c b/src/plugins/preauth/pkinit/pkinit_constants.c
index 905e90d29c..a32b373c32 100644
--- a/src/plugins/preauth/pkinit/pkinit_constants.c
+++ b/src/plugins/preauth/pkinit/pkinit_constants.c
@@ -34,25 +34,49 @@
/* RFC 8636 id-pkinit-kdf-ah-sha1: iso(1) identified-organization(3) dod(6)
* internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha1(1) */
-static char sha1_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x01 };
+static char kdf_sha1[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x01 };
/* RFC 8636 id-pkinit-kdf-ah-sha256: iso(1) identified-organization(3) dod(6)
* internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha256(2) */
-static char sha256_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x02 };
+static char kdf_sha256[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x02 };
/* RFC 8636 id-pkinit-kdf-ah-sha512: iso(1) identified-organization(3) dod(6)
* internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha512(3) */
-static char sha512_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x03 };
+static char kdf_sha512[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x03 };
-const krb5_data sha1_id = { KV5M_DATA, sizeof(sha1_oid), sha1_oid };
-const krb5_data sha256_id = { KV5M_DATA, sizeof(sha256_oid), sha256_oid };
-const krb5_data sha512_id = { KV5M_DATA, sizeof(sha512_oid), sha512_oid };
+const krb5_data kdf_sha1_id = { KV5M_DATA, sizeof(kdf_sha1), kdf_sha1 };
+const krb5_data kdf_sha256_id = { KV5M_DATA, sizeof(kdf_sha256), kdf_sha256 };
+const krb5_data kdf_sha512_id = { KV5M_DATA, sizeof(kdf_sha512), kdf_sha512 };
krb5_data const * const supported_kdf_alg_ids[] = {
- &sha256_id,
- &sha1_id,
- &sha512_id,
+ &kdf_sha256_id,
+ &kdf_sha1_id,
+ &kdf_sha512_id,
NULL
};
+/* RFC 3370 sha-1: iso(1) identified-organization(3) oiw(14) secsig(3)
+ * algorithm(2) 26 */
+static char cms_sha1[] = { 0x2b, 0x0e, 0x03, 0x02, 0x1a };
+/* RFC 5754 id-sha256: joint-iso-itu-t(2) country(16) us(840) organization(1)
+ * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 */
+static char cms_sha256[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+/* RFC 5754 id-sha384: joint-iso-itu-t(2) country(16) us(840) organization(1)
+ * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 */
+static char cms_sha384[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+/* RFC 5754 id-sha512: joint-iso-itu-t(2) country(16) us(840) organization(1)
+ * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 */
+static char cms_sha512[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+const krb5_data cms_sha1_id = { KV5M_DATA, sizeof(cms_sha1), cms_sha1 };
+const krb5_data cms_sha256_id = { KV5M_DATA, sizeof(cms_sha256), cms_sha256 };
+const krb5_data cms_sha384_id = { KV5M_DATA, sizeof(cms_sha384), cms_sha384 };
+const krb5_data cms_sha512_id = { KV5M_DATA, sizeof(cms_sha512), cms_sha512 };
+
/* RFC 4055 sha256WithRSAEncryption: iso(1) member-body(2) us(840)
* rsadsi(113549) pkcs(1) 1 11 */
static char sha256WithRSAEncr_oid[9] = {
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index fd876e4850..3b12e904b1 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -562,9 +562,13 @@ pkinit_alg_agility_kdf(krb5_context context,
krb5_data *pk_as_rep,
krb5_keyblock *key_block);
-extern const krb5_data sha1_id;
-extern const krb5_data sha256_id;
-extern const krb5_data sha512_id;
+extern const krb5_data kdf_sha1_id;
+extern const krb5_data kdf_sha256_id;
+extern const krb5_data kdf_sha512_id;
+extern const krb5_data cms_sha1_id;
+extern const krb5_data cms_sha256_id;
+extern const krb5_data cms_sha384_id;
+extern const krb5_data cms_sha512_id;
extern const krb5_data oakley_1024;
extern const krb5_data oakley_2048;
extern const krb5_data oakley_4096;
@@ -597,4 +601,18 @@ crypto_req_cert_matching_data(krb5_context context,
int parse_dh_min_bits(krb5_context context, const char *str);
+/* Generate a SHA-1 checksum over body in *cksum1_out and a SHA-256 checksum
+ * over body in *cksum2_out with appropriate metadata. */
+krb5_error_code
+crypto_generate_checksums(krb5_context context, const krb5_data *body,
+ krb5_data *cksum1_out,
+ krb5_pachecksum2 **cksum2_out);
+
+/* Verify the SHA-1 checksum in cksum1 and the tagged checksum in cksum2.
+ * cksum2 may be NULL, in which case only cksum1 is verified. */
+krb5_error_code
+crypto_verify_checksums(krb5_context context, krb5_data *body,
+ const krb5_data *cksum1,
+ const krb5_pachecksum2 *cksum2);
+
#endif /* _PKINIT_CRYPTO_H */
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 402bf1b9b3..429b7d202c 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -2616,11 +2616,11 @@ cleanup:
static const EVP_MD *
algid_to_md(const krb5_data *alg_id)
{
- if (data_eq(*alg_id, sha1_id))
+ if (data_eq(*alg_id, kdf_sha1_id))
return EVP_sha1();
- if (data_eq(*alg_id, sha256_id))
+ if (data_eq(*alg_id, kdf_sha256_id))
return EVP_sha256();
- if (data_eq(*alg_id, sha512_id))
+ if (data_eq(*alg_id, kdf_sha512_id))
return EVP_sha512();
return NULL;
}
@@ -5663,3 +5663,113 @@ parse_dh_min_bits(krb5_context context, const char *str)
TRACE_PKINIT_DH_INVALID_MIN_BITS(context, str);
return PKINIT_DEFAULT_DH_MIN_BITS;
}
+
+/* Return the OpenSSL message digest type matching the given CMS OID, or NULL
+ * if it doesn't match any of the CMS OIDs we know about. */
+static const EVP_MD *
+md_from_cms_oid(const krb5_data *alg_id)
+{
+ if (data_eq(*alg_id, cms_sha1_id))
+ return EVP_sha1();
+ if (data_eq(*alg_id, cms_sha256_id))
+ return EVP_sha256();
+ if (data_eq(*alg_id, cms_sha384_id))
+ return EVP_sha384();
+ if (data_eq(*alg_id, cms_sha512_id))
+ return EVP_sha512();
+ return NULL;
+}
+
+/* Compute a message digest of the given type over body, placing the result in
+ * *digest_out in allocated storage. Return true on success. */
+static krb5_boolean
+make_digest(const krb5_data *body, const EVP_MD *md, krb5_data *digest_out)
+{
+ krb5_error_code ret;
+ krb5_data d;
+
+ if (md == NULL)
+ return FALSE;
+ ret = alloc_data(&d, EVP_MD_size(md));
+ if (ret)
+ return FALSE;
+ if (!EVP_Digest(body->data, body->length, (uint8_t *)d.data, &d.length, md,
+ NULL)) {
+ free(d.data);
+ return FALSE;
+ }
+ *digest_out = d;
+ return TRUE;
+}
+
+/* Return true if digest verifies for the given body and message digest
+ * type. */
+static krb5_boolean
+check_digest(const krb5_data *body, const EVP_MD *md, const krb5_data *digest)
+{
+ unsigned int digest_len;
+ uint8_t buf[EVP_MAX_MD_SIZE];
+
+ if (md == NULL)
+ return FALSE;
+ if (!EVP_Digest(body->data, body->length, buf, &digest_len, md, NULL))
+ return FALSE;
+ return (digest->length == digest_len &&
+ CRYPTO_memcmp(digest->data, buf, digest_len) == 0);
+}
+
+krb5_error_code
+crypto_generate_checksums(krb5_context context, const krb5_data *body,
+ krb5_data *cksum1_out, krb5_pachecksum2 **cksum2_out)
+{
+ krb5_data cksum1 = empty_data();
+ krb5_pachecksum2 *cksum2 = NULL;
+ krb5_error_code ret;
+
+ if (!make_digest(body, EVP_sha1(), &cksum1))
+ goto fail;
+
+ cksum2 = k5alloc(sizeof(*cksum2), &ret);
+ if (cksum2 == NULL)
+ goto fail;
+
+ if (!make_digest(body, EVP_sha256(), &cksum2->checksum))
+ goto fail;
+
+ if (krb5int_copy_data_contents(context, &cms_sha256_id,
+ &cksum2->algorithmIdentifier.algorithm))
+ goto fail;
+
+ cksum2->algorithmIdentifier.parameters = empty_data();
+
+ *cksum1_out = cksum1;
+ *cksum2_out = cksum2;
+ return 0;
+
+fail:
+ krb5_free_data_contents(context, &cksum1);
+ free_pachecksum2(context, &cksum2);
+ return KRB5_CRYPTO_INTERNAL;
+}
+
+krb5_error_code
+crypto_verify_checksums(krb5_context context, krb5_data *body,
+ const krb5_data *cksum1,
+ const krb5_pachecksum2 *cksum2)
+{
+ const EVP_MD *md;
+
+ /* RFC 4556 doesn't say what error to return if the checksum doesn't match.
+ * Windows returns this one. */
+ if (!check_digest(body, EVP_sha1(), cksum1))
+ return KRB5KRB_AP_ERR_MODIFIED;
+
+ if (cksum2 == NULL)
+ return 0;
+
+ md = md_from_cms_oid(&cksum2->algorithmIdentifier.algorithm);
+ if (!check_digest(body, md, &cksum2->checksum))
+ return KRB5KRB_AP_ERR_MODIFIED;
+
+ return 0;
+}
diff --git a/src/plugins/preauth/pkinit/pkinit_kdf_test.c b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
index 99c93ac128..dd6e8d7503 100644
--- a/src/plugins/preauth/pkinit/pkinit_kdf_test.c
+++ b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
@@ -126,7 +126,7 @@ main(int argc, char **argv)
/* TEST 1: SHA-1/AES */
/* set up algorithm id */
- alg_id.algorithm = sha1_id;
+ alg_id.algorithm = kdf_sha1_id;
enctype = enctype_aes;
@@ -157,7 +157,7 @@ main(int argc, char **argv)
/* TEST 2: SHA-256/AES */
/* set up algorithm id */
- alg_id.algorithm = sha256_id;
+ alg_id.algorithm = kdf_sha256_id;
enctype = enctype_aes;
diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c
index 25965eb5d2..891f47fd26 100644
--- a/src/plugins/preauth/pkinit/pkinit_lib.c
+++ b/src/plugins/preauth/pkinit/pkinit_lib.c
@@ -29,6 +29,7 @@
* SUCH DAMAGES.
*/
+#include "k5-int.h"
#include "pkinit.h"
#define FAKECERT
@@ -119,8 +120,9 @@ free_krb5_auth_pack(krb5_auth_pack **in)
{
if ((*in) == NULL) return;
krb5_free_data_contents(NULL, &(*in)->clientPublicValue);
- free((*in)->pkAuthenticator.paChecksum.contents);
+ free((*in)->pkAuthenticator.paChecksum.data);
krb5_free_data(NULL, (*in)->pkAuthenticator.freshnessToken);
+ free_pachecksum2(NULL, &(*in)->pkAuthenticator.paChecksum2);
if ((*in)->supportedCMSTypes != NULL)
free_krb5_algorithm_identifiers(&((*in)->supportedCMSTypes));
if ((*in)->supportedKDFs) {
@@ -196,6 +198,18 @@ free_krb5_kdc_dh_key_info(krb5_kdc_dh_key_info **in)
free(*in);
}
+void
+free_pachecksum2(krb5_context context, krb5_pachecksum2 **in)
+{
+ if (*in == NULL)
+ return;
+ krb5_free_data_contents(context, &(*in)->checksum);
+ krb5_free_data_contents(context, &(*in)->algorithmIdentifier.algorithm);
+ krb5_free_data_contents(context, &(*in)->algorithmIdentifier.parameters);
+ free(*in);
+ *in = NULL;
+}
+
void
init_krb5_pa_pk_as_req(krb5_pa_pk_as_req **in)
{
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index e22bcb195b..f558308483 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -428,11 +428,12 @@ pkinit_server_verify_padata(krb5_context context,
krb5_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
krb5_pa_pk_as_req *reqp = NULL;
krb5_auth_pack *auth_pack = NULL;
+ krb5_pk_authenticator *pka;
pkinit_kdc_context plgctx = NULL;
pkinit_kdc_req_context reqctx = NULL;
krb5_checksum cksum = {0, 0, 0, NULL};
krb5_data *der_req = NULL;
- krb5_data k5data, *ftoken;
+ krb5_data k5data;
int is_signed = 1;
krb5_pa_data **e_data = NULL;
krb5_kdcpreauth_modreq modreq = NULL;
@@ -524,8 +525,9 @@ pkinit_server_verify_padata(krb5_context context,
pkiDebug("failed to decode krb5_auth_pack\n");
goto cleanup;
}
+ pka = &auth_pack->pkAuthenticator;
- retval = krb5_check_clockskew(context, auth_pack->pkAuthenticator.ctime);
+ retval = krb5_check_clockskew(context, pka->ctime);
if (retval)
goto cleanup;
@@ -548,36 +550,14 @@ pkinit_server_verify_padata(krb5_context context,
goto cleanup;
}
der_req = cb->request_body(context, rock);
- 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;
- }
- if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
- k5_bcmp(cksum.contents, auth_pack->pkAuthenticator.paChecksum.contents,
- cksum.length) != 0) {
- pkiDebug("failed to match the checksum\n");
-#ifdef DEBUG_CKSUM
- pkiDebug("calculating checksum on buf size (%d)\n", req_pkt->length);
- print_buffer(req_pkt->data, req_pkt->length);
- pkiDebug("received checksum type=%d size=%d ",
- auth_pack->pkAuthenticator.paChecksum.checksum_type,
- auth_pack->pkAuthenticator.paChecksum.length);
- print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
- auth_pack->pkAuthenticator.paChecksum.length);
- pkiDebug("expected checksum type=%d size=%d ",
- cksum.checksum_type, cksum.length);
- print_buffer(cksum.contents, cksum.length);
-#endif
- retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
+ retval = crypto_verify_checksums(context, der_req, &pka->paChecksum,
+ pka->paChecksum2);
+ if (retval)
goto cleanup;
- }
- ftoken = auth_pack->pkAuthenticator.freshnessToken;
- if (ftoken != NULL) {
- retval = cb->check_freshness_token(context, rock, ftoken);
+ if (pka->freshnessToken != NULL) {
+ retval = cb->check_freshness_token(context, rock, pka->freshnessToken);
if (retval)
goto cleanup;
valid_freshness_token = TRUE;
diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
index 1faa6816d7..7b68d4b3b1 100644
--- a/src/plugins/preauth/pkinit/pkinit_trace.h
+++ b/src/plugins/preauth/pkinit/pkinit_trace.h
@@ -58,8 +58,9 @@
TRACE(c, "PKINIT client verified DH reply")
#define TRACE_PKINIT_CLIENT_REP_DH_FAIL(c) \
TRACE(c, "PKINIT client could not verify DH reply")
-#define TRACE_PKINIT_CLIENT_REQ_CHECKSUM(c, cksum) \
- TRACE(c, "PKINIT client computed kdc-req-body checksum {cksum}", cksum)
+#define TRACE_PKINIT_CLIENT_REQ_CHECKSUMS(c, ck1, ck2) \
+ TRACE(c, "PKINIT client computed checksums: {hexdata} {hexdata}", \
+ ck1, &(ck2)->checksum)
#define TRACE_PKINIT_CLIENT_REQ_DH(c) \
TRACE(c, "PKINIT client making DH request")
#define TRACE_PKINIT_CLIENT_SAN_CONFIG_DNSNAME(c, host) \
diff --git a/src/tests/asn.1/krb5_decode_test.c b/src/tests/asn.1/krb5_decode_test.c
index 2fa6dce8eb..f47849abad 100644
--- a/src/tests/asn.1/krb5_decode_test.c
+++ b/src/tests/asn.1/krb5_decode_test.c
@@ -1174,7 +1174,7 @@ main(int argc, char **argv)
/* decode_krb5_auth_pack */
{
setup(krb5_auth_pack,ktest_make_sample_auth_pack);
- decode_run("krb5_auth_pack","","30 81 85 A0 35 30 33 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 06 04 04 31 32 33 34 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61",
+ decode_run("krb5_auth_pack","","30 81 89 A0 39 30 37 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61",
acc.decode_krb5_auth_pack,
ktest_equal_auth_pack,ktest_free_auth_pack);
ktest_empty_auth_pack(&ref);
diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c
index d37e4fa7e6..7f54aa3184 100644
--- a/src/tests/asn.1/ktest.c
+++ b/src/tests/asn.1/ktest.c
@@ -700,9 +700,7 @@ ktest_make_sample_pk_authenticator(krb5_pk_authenticator *p)
p->cusec = SAMPLE_USEC;
p->ctime = SAMPLE_TIME;
p->nonce = SAMPLE_NONCE;
- ktest_make_sample_checksum(&p->paChecksum);
- /* We don't encode the checksum type, only the contents. */
- p->paChecksum.checksum_type = 0;
+ ktest_make_sample_data(&p->paChecksum);
p->freshnessToken = ealloc(sizeof(krb5_data));
ktest_make_sample_data(p->freshnessToken);
}
@@ -1604,8 +1602,7 @@ ktest_empty_pa_otp_req(krb5_pa_otp_req *p)
static void
ktest_empty_pk_authenticator(krb5_pk_authenticator *p)
{
- ktest_empty_checksum(&p->paChecksum);
- p->paChecksum.contents = NULL;
+ ktest_empty_data(&p->paChecksum);
krb5_free_data(NULL, p->freshnessToken);
p->freshnessToken = NULL;
}
diff --git a/src/tests/asn.1/ktest_equal.c b/src/tests/asn.1/ktest_equal.c
index b48a0285d2..13786dd1e5 100644
--- a/src/tests/asn.1/ktest_equal.c
+++ b/src/tests/asn.1/ktest_equal.c
@@ -844,7 +844,7 @@ ktest_equal_pk_authenticator(krb5_pk_authenticator *ref,
p = p && scalar_equal(cusec);
p = p && scalar_equal(ctime);
p = p && scalar_equal(nonce);
- p = p && struct_equal(paChecksum, ktest_equal_checksum);
+ p = p && data_eq(ref->paChecksum, var->paChecksum);
return p;
}
diff --git a/src/tests/asn.1/pkinit_encode.out b/src/tests/asn.1/pkinit_encode.out
index 6ec7aaa36a..a764182e15 100644
--- a/src/tests/asn.1/pkinit_encode.out
+++ b/src/tests/asn.1/pkinit_encode.out
@@ -1,7 +1,7 @@
encode_krb5_pa_pk_as_req: 30 38 80 08 6B 72 62 35 64 61 74 61 A1 22 30 20 30 1E 80 08 6B 72 62 35 64 61 74 61 81 08 6B 72 62 35 64 61 74 61 82 08 6B 72 62 35 64 61 74 61 82 08 6B 72 62 35 64 61 74 61
encode_krb5_pa_pk_as_rep(dhInfo): A0 28 30 26 80 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61 A2 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
encode_krb5_pa_pk_as_rep(encKeyPack): 81 08 6B 72 62 35 64 61 74 61
-encode_krb5_auth_pack: 30 81 85 A0 35 30 33 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 06 04 04 31 32 33 34 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
+encode_krb5_auth_pack: 30 81 89 A0 39 30 37 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
encode_krb5_kdc_dh_key_info: 30 25 A0 0B 03 09 00 6B 72 62 35 64 61 74 61 A1 03 02 01 2A A2 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A
encode_krb5_reply_key_pack: 30 26 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
encode_krb5_sp80056a_other_info: 30 81 81 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A0 32 04 30 30 2E A0 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 32 04 30 30 2E A0 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 0A 04 08 6B 72 62 35 64 61 74 61
diff --git a/src/tests/asn.1/pkinit_trval.out b/src/tests/asn.1/pkinit_trval.out
index 46f4a34108..c47bd71f67 100644
--- a/src/tests/asn.1/pkinit_trval.out
+++ b/src/tests/asn.1/pkinit_trval.out
@@ -38,7 +38,7 @@ encode_krb5_auth_pack:
. . [0] [Integer] 123456
. . [1] [Generalized Time] "19940610060317Z"
. . [2] [Integer] 42
-. . [3] [Octet String] "1234"
+. . [3] [Octet String] "krb5data"
. . [4] [Octet String] "krb5data"
. [1] [Octet String] "pvalue"
. [2] [Sequence/Sequence Of]
--
2.49.0

View file

@ -1,381 +0,0 @@
From 33afd2a6cfdf87d153170b41fbabfb92be49c422 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 10 Apr 2025 10:04:22 +0200
Subject: [PATCH] [downstream] Do not block HMAC-MD4/5 in FIPS mode
To ensure RC4 HMAC-MD5 was not used in FIPS mode, access to HMAC-MD4/5
was not allowed in this mode. However, since we provide the
"radius_md5_fips_override" configuration parameter to allow using RADIUS
regardless to the FIPS restrictions, we should allow HMAC-MD5 to be used
too in this case, because it is required for the newly supported
Message-Authenticator attribute.
A FIPS mode check is added in calculate_mac() which will fail if
"radius_md5_fips_override" is not true. It will not affect interactions
between krb5kdc and ipa-otpd, because the Message-Authenticator
attribute is not generated in this case.
---
src/lib/crypto/krb/crypto_int.h | 9 +++
src/lib/crypto/openssl/Makefile.in | 9 ++-
src/lib/crypto/openssl/common.c | 80 +++++++++++++++++++
.../crypto/openssl/hash_provider/hash_evp.c | 62 ++------------
src/lib/crypto/openssl/hmac.c | 15 ++--
src/lib/krad/packet.c | 19 +++--
6 files changed, 120 insertions(+), 74 deletions(-)
create mode 100644 src/lib/crypto/openssl/common.c
diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h
index 1ee4b30e02..ff67b6bd35 100644
--- a/src/lib/crypto/krb/crypto_int.h
+++ b/src/lib/crypto/krb/crypto_int.h
@@ -36,6 +36,9 @@
#include <openssl/opensslv.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+#include <openssl/provider.h>
+
/*
* OpenSSL 3.0 relegates MD4 and RC4 to the legacy provider, which must be
* explicitly loaded into a library context. Performing this loading within a
@@ -660,4 +663,10 @@ iov_cursor_advance(struct iov_cursor *c, size_t nblocks)
c->out_pos += nblocks * c->block_size;
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+krb5_error_code k5_get_ossl_legacy_libctx(OSSL_LIB_CTX **libctx);
+
+#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
+
#endif /* CRYPTO_INT_H */
diff --git a/src/lib/crypto/openssl/Makefile.in b/src/lib/crypto/openssl/Makefile.in
index 8e4cdb8bbf..cc131000bd 100644
--- a/src/lib/crypto/openssl/Makefile.in
+++ b/src/lib/crypto/openssl/Makefile.in
@@ -8,21 +8,24 @@ STLIBOBJS=\
hmac.o \
kdf.o \
pbkdf2.o \
- sha256.o
+ sha256.o \
+ common.o
OBJS=\
$(OUTPRE)cmac.$(OBJEXT) \
$(OUTPRE)hmac.$(OBJEXT) \
$(OUTPRE)kdf.$(OBJEXT) \
$(OUTPRE)pbkdf2.$(OBJEXT) \
- $(OUTPRE)sha256.$(OBJEXT)
+ $(OUTPRE)sha256.$(OBJEXT) \
+ $(OUTPRE)common.$(OBJEXT)
SRCS=\
$(srcdir)/cmac.c \
$(srcdir)/hmac.c \
$(srcdir)/kdf.c \
$(srcdir)/pbkdf2.c \
- $(srcdir)/sha256.c
+ $(srcdir)/sha256.c \
+ $(srcdir)/common.c
SUBDIROBJLISTS= md4/OBJS.ST \
md5/OBJS.ST sha1/OBJS.ST sha2/OBJS.ST \
diff --git a/src/lib/crypto/openssl/common.c b/src/lib/crypto/openssl/common.c
new file mode 100644
index 0000000000..ced43fd54c
--- /dev/null
+++ b/src/lib/crypto/openssl/common.c
@@ -0,0 +1,80 @@
+#include "crypto_int.h"
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+#include <openssl/provider.h>
+#include <openssl/fips.h>
+#include <threads.h>
+#include <stdbool.h>
+
+typedef struct ossl_legacy_context {
+ bool initialized;
+ OSSL_LIB_CTX *libctx;
+ OSSL_PROVIDER *default_provider;
+ OSSL_PROVIDER *legacy_provider;
+} ossl_legacy_context_t;
+
+static thread_local ossl_legacy_context_t g_ossl_legacy_ctx;
+
+static krb5_error_code
+init_ossl_legacy_ctx(ossl_legacy_context_t *ctx)
+{
+ 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;
+
+ ctx->initialized = true;
+ return 0;
+}
+
+static void
+deinit_ossl_legacy_ctx(ossl_legacy_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);
+
+ ctx->initialized = false;
+}
+
+krb5_error_code
+k5_get_ossl_legacy_libctx(OSSL_LIB_CTX **libctx)
+{
+ krb5_error_code err;
+
+ if (!FIPS_mode()) {
+ if (libctx)
+ *libctx = NULL;
+ err = 0;
+ goto end;
+ }
+
+ if (!g_ossl_legacy_ctx.initialized) {
+ err = init_ossl_legacy_ctx(&g_ossl_legacy_ctx);
+ if (err) {
+ deinit_ossl_legacy_ctx(&g_ossl_legacy_ctx);
+ goto end;
+ }
+ }
+
+ if (libctx)
+ *libctx = g_ossl_legacy_ctx.libctx;
+ err = 0;
+
+end:
+ return err;
+}
+
+#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
index eb2e693e9f..2fd5d383d6 100644
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
@@ -44,48 +44,7 @@
#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,
@@ -120,25 +79,14 @@ hash_legacy_evp(const char *algo, const krb5_crypto_iov *data, size_t num_data,
krb5_data *output)
{
krb5_error_code err;
+ OSSL_LIB_CTX *ossl_libctx;
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;
- }
- }
+ err = k5_get_ossl_legacy_libctx(&ossl_libctx);
+ if (err)
+ goto end;
- md = EVP_MD_fetch(ossl_md_ctx->libctx, algo, NULL);
+ md = EVP_MD_fetch(ossl_libctx, algo, NULL);
if (!md) {
err = KRB5_CRYPTO_INTERNAL;
goto end;
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
index 25a419d73a..8f9e88fec9 100644
--- a/src/lib/crypto/openssl/hmac.c
+++ b/src/lib/crypto/openssl/hmac.c
@@ -59,7 +59,6 @@
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/params.h>
#include <openssl/core_names.h>
-#include <openssl/fips.h>
#else
#include <openssl/hmac.h>
#endif
@@ -112,11 +111,7 @@ map_digest(const struct krb5_hash_provider *hash)
return EVP_sha256();
else if (hash == &krb5int_hash_sha384)
return EVP_sha384();
-
- if (FIPS_mode())
- return NULL;
-
- if (hash == &krb5int_hash_md5)
+ else if (hash == &krb5int_hash_md5)
return EVP_md5();
else if (hash == &krb5int_hash_md4)
return EVP_md4();
@@ -138,13 +133,19 @@ krb5int_hmac_keyblock(const struct krb5_hash_provider *hash,
EVP_MAC_CTX *ctx = NULL;
OSSL_PARAM params[2], *p = params;
size_t i = 0, md_len;
+ OSSL_LIB_CTX *ossl_libctx;
+ krb5_error_code err;
if (md == NULL || keyblock->length > hash->blocksize)
return KRB5_CRYPTO_INTERNAL;
if (output->length < hash->hashsize)
return KRB5_BAD_MSIZE;
- mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ err = k5_get_ossl_legacy_libctx(&ossl_libctx);
+ if (err)
+ return err;
+
+ mac = EVP_MAC_fetch(ossl_libctx, "HMAC", NULL);
if (mac == NULL)
return KRB5_CRYPTO_INTERNAL;
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
index 3c1a4d507e..b95c99df65 100644
--- a/src/lib/krad/packet.c
+++ b/src/lib/krad/packet.c
@@ -278,7 +278,7 @@ lookup_msgauth_addr(const krad_packet *pkt)
* auth, which may be from pkt or from a corresponding request.
*/
static krb5_error_code
-calculate_mac(const char *secret, const krad_packet *pkt,
+calculate_mac(krb5_context ctx, const char *secret, const krad_packet *pkt,
const uint8_t auth[AUTH_FIELD_SIZE],
uint8_t mac_out[MD5_DIGEST_SIZE])
{
@@ -288,6 +288,10 @@ calculate_mac(const char *secret, const krad_packet *pkt,
krb5_crypto_iov input[5];
krb5_data ksecr, mac;
+ /* Do not use HMAC-MD5 if not explicitly allowed */
+ if (kr_use_fips(ctx))
+ return KRB5_CRYPTO_INTERNAL;
+
msgauth_attr = lookup_msgauth_addr(pkt);
if (msgauth_attr == NULL)
return EINVAL;
@@ -393,7 +397,8 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
if (msgauth_required) {
/* Calculate and set the Message-Authenticator MAC. */
- retval = calculate_mac(secret, pkt, pkt_auth(pkt), pkt_attr(pkt) + 2);
+ retval = calculate_mac(ctx, secret, pkt, pkt_auth(pkt),
+ pkt_attr(pkt) + 2);
if (retval != 0)
goto error;
}
@@ -454,7 +459,7 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
* section 5.14, use the authenticator from the request, not from the
* response.
*/
- retval = calculate_mac(secret, pkt, pkt_auth(request),
+ retval = calculate_mac(ctx, secret, pkt, pkt_auth(request),
pkt_attr(pkt) + 2);
if (retval != 0)
goto error;
@@ -476,7 +481,7 @@ error:
/* Verify the Message-Authenticator value in pkt, using the provided
* authenticator (which may be from pkt or from a corresponding request). */
static krb5_error_code
-verify_msgauth(const char *secret, const krad_packet *pkt,
+verify_msgauth(krb5_context ctx, const char *secret, const krad_packet *pkt,
const uint8_t auth[AUTH_FIELD_SIZE])
{
uint8_t mac[MD5_DIGEST_SIZE];
@@ -488,7 +493,7 @@ verify_msgauth(const char *secret, const krad_packet *pkt,
if (msgauth == NULL)
return ENODATA;
- retval = calculate_mac(secret, pkt, auth, mac);
+ retval = calculate_mac(ctx, secret, pkt, auth, mac);
if (retval)
return retval;
@@ -561,7 +566,7 @@ krad_packet_decode_request(krb5_context ctx, const char *secret,
/* Verify Message-Authenticator if present. */
if (has_pkt_msgauth(req)) {
- retval = verify_msgauth(secret, req, pkt_auth(req));
+ retval = verify_msgauth(ctx, secret, req, pkt_auth(req));
if (retval) {
krad_packet_free(req);
return retval;
@@ -613,7 +618,7 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
/* Verify Message-Authenticator if present. */
if (has_pkt_msgauth(*rsppkt)) {
- if (verify_msgauth(secret, *rsppkt, pkt_auth(tmp)) != 0)
+ if (verify_msgauth(ctx, secret, *rsppkt, pkt_auth(tmp)) != 0)
continue;
}
--
2.49.0

View file

@ -1,189 +0,0 @@
From 1761e06398e4f043e4f540f57131c37fcc53a1b9 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Wed, 10 Dec 2025 10:42:02 +0200
Subject: [PATCH] Fix strchr() conformance to C23
C23 7.28.5.1 specifies search functions such as strchr() as generic,
returning const char * if the first argument is of type const char *.
Fix uses of strchr() to conform to this change.
[jrische@redhat.com: altered changes to avoid casts; fixed an
additional case]
[ghudson@mit.edu: condensed some declarations; rewrote commit message]
ticket: 9191 (new)
(cherry picked from commit 6cd8580d823585d50ee4f30efd9f7e855823a369)
---
src/lib/krb5/ccache/ccbase.c | 4 ++--
src/lib/krb5/os/expand_path.c | 3 ++-
src/lib/krb5/os/locate_kdc.c | 15 +++++++--------
src/plugins/preauth/pkinit/pkinit_crypto.h | 2 +-
.../preauth/pkinit/pkinit_crypto_openssl.c | 6 +++---
src/plugins/preauth/pkinit/pkinit_identity.c | 2 +-
src/plugins/preauth/pkinit/pkinit_matching.c | 2 +-
src/tests/responder.c | 3 +--
8 files changed, 18 insertions(+), 19 deletions(-)
diff --git a/src/lib/krb5/ccache/ccbase.c b/src/lib/krb5/ccache/ccbase.c
index 5a01320832..1aada91b5e 100644
--- a/src/lib/krb5/ccache/ccbase.c
+++ b/src/lib/krb5/ccache/ccbase.c
@@ -201,8 +201,8 @@ krb5_cc_register(krb5_context context, const krb5_cc_ops *ops,
krb5_error_code KRB5_CALLCONV
krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
{
- char *pfx, *cp;
- const char *resid;
+ char *pfx;
+ const char *cp, *resid;
unsigned int pfxlen;
krb5_error_code err;
const krb5_cc_ops *ops;
diff --git a/src/lib/krb5/os/expand_path.c b/src/lib/krb5/os/expand_path.c
index 5cbccf08c8..6569b8820b 100644
--- a/src/lib/krb5/os/expand_path.c
+++ b/src/lib/krb5/os/expand_path.c
@@ -454,7 +454,8 @@ k5_expand_path_tokens_extra(krb5_context context, const char *path_in,
{
krb5_error_code ret;
struct k5buf buf;
- char *tok_begin, *tok_end, *tok_val, **extra_tokens = NULL, *path;
+ const char *tok_begin, *tok_end;
+ char *tok_val, **extra_tokens = NULL, *path;
const char *path_left;
size_t nargs = 0, i;
va_list ap;
diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c
index edca5ac7eb..47e15c849f 100644
--- a/src/lib/krb5/os/locate_kdc.c
+++ b/src/lib/krb5/os/locate_kdc.c
@@ -188,8 +188,8 @@ oom:
}
static void
-parse_uri_if_https(const char *host_or_uri, k5_transport *transport,
- const char **host, const char **uri_path)
+parse_uri_if_https(char *host_or_uri, k5_transport *transport,
+ char **host, const char **uri_path)
{
char *cp;
@@ -229,8 +229,7 @@ locate_srv_conf_1(krb5_context context, const krb5_data *realm,
k5_transport transport, int udpport)
{
const char *realm_srv_names[4];
- char **hostlist = NULL, *realmstr = NULL, *host = NULL;
- const char *hostspec;
+ char **hostlist = NULL, *realmstr = NULL, *host = NULL, *hostspec;
krb5_error_code code;
int i, default_port;
@@ -535,8 +534,8 @@ prof_locate_server(krb5_context context, const krb5_data *realm,
* Return a NULL *host_out if there are any problems parsing the URI.
*/
static void
-parse_uri_fields(const char *uri, k5_transport *transport_out,
- const char **host_out, int *primary_out)
+parse_uri_fields(char *uri, k5_transport *transport_out,
+ char **host_out, int *primary_out)
{
k5_transport transport;
@@ -604,8 +603,8 @@ locate_uri(krb5_context context, const krb5_data *realm,
krb5_error_code ret;
k5_transport transport, host_trans;
struct srv_dns_entry *answers, *entry;
- char *host;
- const char *host_field, *path;
+ char *host, *host_field;
+ const char *path;
int port, def_port, primary;
ret = k5_make_uri_query(context, realm, req_service, &answers);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 3b12e904b1..99e2394040 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -456,7 +456,7 @@ krb5_error_code crypto_load_cas_and_crls
defines the storage type (file, directory, etc) */
int catype, /* IN
defines the ca type (anchor, intermediate, crls) */
- char *id); /* IN
+ const char *id); /* IN
defines the location (filename, directory name, etc) */
/*
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 429b7d202c..6013080afc 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -4956,7 +4956,7 @@ load_cas_and_crls(krb5_context context,
pkinit_req_crypto_context req_cryptoctx,
pkinit_identity_crypto_context id_cryptoctx,
int catype,
- char *filename)
+ const char *filename)
{
STACK_OF(X509_INFO) *sk = NULL;
STACK_OF(X509) *ca_certs = NULL;
@@ -5114,7 +5114,7 @@ load_cas_and_crls_dir(krb5_context context,
pkinit_req_crypto_context req_cryptoctx,
pkinit_identity_crypto_context id_cryptoctx,
int catype,
- char *dirname)
+ const char *dirname)
{
krb5_error_code retval = EINVAL;
DIR *d = NULL;
@@ -5166,7 +5166,7 @@ crypto_load_cas_and_crls(krb5_context context,
pkinit_identity_crypto_context id_cryptoctx,
int idtype,
int catype,
- char *id)
+ const char *id)
{
switch (idtype) {
case IDTYPE_FILE:
diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c
index a5a979f279..b06d519c66 100644
--- a/src/plugins/preauth/pkinit/pkinit_identity.c
+++ b/src/plugins/preauth/pkinit/pkinit_identity.c
@@ -474,7 +474,7 @@ process_option_ca_crl(krb5_context context,
const char *value,
int catype)
{
- char *residual;
+ const char *residual;
unsigned int typelen;
int idtype;
diff --git a/src/plugins/preauth/pkinit/pkinit_matching.c b/src/plugins/preauth/pkinit/pkinit_matching.c
index b42485a50a..5a7f2ba3fa 100644
--- a/src/plugins/preauth/pkinit/pkinit_matching.c
+++ b/src/plugins/preauth/pkinit/pkinit_matching.c
@@ -263,7 +263,7 @@ parse_rule_component(krb5_context context,
char err_buf[128];
int ret;
struct keyword_desc *kw, *nextkw;
- char *nk;
+ const char *nk;
int found_next_kw = 0;
char *value = NULL;
size_t len;
diff --git a/src/tests/responder.c b/src/tests/responder.c
index 82f870ea5d..4221a20283 100644
--- a/src/tests/responder.c
+++ b/src/tests/responder.c
@@ -282,8 +282,7 @@ responder(krb5_context ctx, void *rawdata, krb5_responder_context rctx)
/* Provide a particular response for an OTP challenge. */
if (data->otp_answer != NULL) {
if (krb5_responder_otp_get_challenge(ctx, rctx, &ochl) == 0) {
- key = strchr(data->otp_answer, '=');
- if (key != NULL) {
+ if (strchr(data->otp_answer, '=') != NULL) {
/* Make a copy of the answer that we can chop up. */
key = strdup(data->otp_answer);
if (key == NULL)
--
2.51.1

View file

@ -1,226 +0,0 @@
From 3baf9b93dc1dfe38585722c71d7268304cb4a01a Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Sun, 21 Sep 2025 11:14:51 +0300
Subject: libkrb5: in case PKINIT is configured, attempt Anonymous
PKINIT for FAST
If auto_fast_armor is configured for the realm or globally, optimistically
assume that Anonymous PKINIT is supported as well and try to obtain it for
FAST use in case no pre-made FAST channel was established by the caller.
This behavior will automatically enable use of passwordless pre-authentication
methods which rely on FAST channel presence in deployments such as FreeIPA.
Notably, Microsoft Active Directory KDCs do not support Anonymous PKINIT. For
these deployments only a machine account (host keytab) can be used to build a
FAST channel. However, libkrb5 does not have access to /etc/krb5.keytab in a
general case.
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
---
src/lib/krb5/krb/fast.c | 118 ++++++++++++++++++++++++++++++++++++++++
src/lib/krb5/krb/fast.h | 2 +
src/man/krb5.conf.man | 13 +++++
3 files changed, 133 insertions(+)
diff --git a/src/lib/krb5/krb/fast.c b/src/lib/krb5/krb/fast.c
index 62c9f0841..ee2e08189 100644
--- a/src/lib/krb5/krb/fast.c
+++ b/src/lib/krb5/krb/fast.c
@@ -168,6 +168,109 @@ krb5int_fast_prep_req_body(krb5_context context,
return retval;
}
+static krb5_boolean
+fast_is_pkinit_allowed(krb5_context context, krb5_data *realm)
+{
+ int value;
+ krb5_error_code retval = EINVAL;
+ char realmstr[1024];
+ const char *option = "auto_fast_armor";
+ const int def_value = FALSE;
+
+ if (realm != NULL && realm->length > sizeof(realmstr)-1)
+ return FALSE;
+
+ if (realm != NULL) {
+ strncpy(realmstr, realm->data, realm->length);
+ realmstr[realm->length] = '\0';
+
+ retval = profile_get_boolean(context->profile,
+ KRB5_CONF_REALMS, realmstr,
+ option, def_value, &value);
+ }
+
+ return retval ? FALSE : value;
+
+}
+
+static krb5_error_code
+fast_acquire_pkinit_armor(krb5_context context,
+ struct krb5int_fast_request_state *state,
+ krb5_get_init_creds_opt *opt, krb5_kdc_req *request)
+{
+ krb5_context ctx;
+ krb5_get_init_creds_opt *options = NULL;
+ krb5_error_code retval = 0;
+ krb5_data *target_realm = &request->server->realm;
+ krb5_creds creds;
+ krb5_principal anon_princ = NULL;
+ krb5_ccache out_cc;
+
+ /* short circuit, we are asked to perform Anonymous PKINIT already */
+ if (opt->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) {
+ return EINVAL;
+ }
+
+ /* skip realms which do not allow use of automated FAST armor */
+ if (!fast_is_pkinit_allowed(context, target_realm)) {
+ return EINVAL;
+ }
+
+ retval = krb5_init_context(&ctx);
+ if (retval != 0) {
+ return retval;
+ }
+ retval = krb5_get_init_creds_opt_alloc(ctx, &options);
+ if (retval != 0) {
+ goto cleanup;
+ }
+ krb5_get_init_creds_opt_set_anonymous(options, 1);
+ retval = krb5_cc_new_unique(ctx, "MEMORY", NULL, &out_cc);
+ if (retval != 0) {
+ goto cleanup;
+ }
+
+ retval = krb5_get_init_creds_opt_set_out_ccache(ctx, options, out_cc);
+ if (retval != 0) {
+ goto cleanup;
+ }
+
+ retval = krb5_build_principal_ext(ctx, &anon_princ,
+ target_realm->length, target_realm->data,
+ strlen(KRB5_WELLKNOWN_NAMESTR),
+ KRB5_WELLKNOWN_NAMESTR,
+ strlen(KRB5_ANONYMOUS_PRINCSTR),
+ KRB5_ANONYMOUS_PRINCSTR, 0);
+ if (retval != 0) {
+ goto cleanup;
+ }
+
+ retval = krb5_get_init_creds_password(ctx, &creds, anon_princ, 0,
+ NULL /* no prompter */, NULL,
+ 0, NULL /* service name */,
+ options);
+ if (retval == 0) {
+ state->fast_state_flags |= KRB5INT_FAST_OWN_ARMOR;
+ state->armor_ccache = out_cc;
+ }
+cleanup:
+ if (retval != 0 && out_cc != NULL) {
+ (void) krb5_cc_destroy(ctx, out_cc);
+ }
+ if (retval == 0) {
+ krb5_free_cred_contents(ctx, &creds);
+ }
+ if (options != NULL) {
+ krb5_get_init_creds_opt_free(ctx, options);
+ }
+ if (anon_princ != NULL) {
+ krb5_free_principal(ctx, anon_princ);
+ }
+ krb5_free_context(ctx);
+
+ return retval;
+}
+
krb5_error_code
krb5int_fast_as_armor(krb5_context context,
struct krb5int_fast_request_state *state,
@@ -178,10 +281,20 @@ krb5int_fast_as_armor(krb5_context context,
krb5_principal target_principal = NULL;
krb5_data *target_realm;
const char *ccname = k5_gic_opt_get_fast_ccache_name(opt);
+ char *fast_ccname = NULL;
krb5_flags fast_flags;
krb5_clear_error_message(context);
target_realm = &request->server->realm;
+ if (ccname == NULL) {
+ retval = fast_acquire_pkinit_armor(context, state, opt, request);
+ if (retval == 0) {
+ retval = krb5_cc_get_full_name(context, state->armor_ccache, &fast_ccname);
+ if (retval == 0 && fast_ccname != NULL)
+ ccname = fast_ccname;
+ }
+ retval = 0;
+ }
if (ccname != NULL) {
TRACE_FAST_ARMOR_CCACHE(context, ccname);
state->fast_state_flags |= KRB5INT_FAST_ARMOR_AVAIL;
@@ -220,6 +333,8 @@ krb5int_fast_as_armor(krb5_context context,
krb5_cc_close(context, ccache);
if (target_principal)
krb5_free_principal(context, target_principal);
+ if (fast_ccname)
+ free(fast_ccname);
return retval;
}
@@ -615,6 +730,9 @@ krb5int_fast_free_state(krb5_context context,
/*We are responsible for none of the store in the fast_outer_req*/
krb5_free_keyblock(context, state->armor_key);
krb5_free_fast_armor(context, state->armor);
+ if (state->fast_state_flags & KRB5INT_FAST_OWN_ARMOR) {
+ krb5_cc_destroy(context, state->armor_ccache);
+ }
free(state);
}
diff --git a/src/lib/krb5/krb/fast.h b/src/lib/krb5/krb/fast.h
index 7156ea203..e5fe8bd54 100644
--- a/src/lib/krb5/krb/fast.h
+++ b/src/lib/krb5/krb/fast.h
@@ -34,6 +34,7 @@ struct krb5int_fast_request_state {
krb5_kdc_req fast_outer_request;
krb5_keyblock *armor_key; /*non-null means fast is in use*/
krb5_fast_armor *armor;
+ krb5_ccache armor_ccache;
krb5_ui_4 fast_state_flags;
krb5_ui_4 fast_options;
krb5_int32 nonce;
@@ -41,6 +42,7 @@ struct krb5int_fast_request_state {
#define KRB5INT_FAST_DO_FAST (1l<<0) /* Perform FAST */
#define KRB5INT_FAST_ARMOR_AVAIL (1l<<1)
+#define KRB5INT_FAST_OWN_ARMOR (1l<<2)
krb5_error_code
krb5int_fast_prep_req_body(krb5_context context,
diff --git a/src/man/krb5.conf.man b/src/man/krb5.conf.man
index d4caa2bd3..ac7649647 100644
--- a/src/man/krb5.conf.man
+++ b/src/man/krb5.conf.man
@@ -650,6 +650,19 @@ primary KDC, in case the user\(aqs password has just been changed, and
the updated database has not been propagated to the replica
servers yet. New in release 1.19.
.TP
+\fBauto_fast_armor\fP
+If this flag is true, then initial ticket request will use Anonymous
+PKINIT to protect the communication as a FAST channel in case an application
+did not provide its own FAST channel. This is useful for deployments where
+pre-authentication methods require use of the FAST channel, such as
+passwordless methods provided by FreeIPA. Microsoft Active Directory
+implementation of PKINIT does not support Anonymous PKINIT feature.
+As a result, \fIauto_fast_armor\fP defaults to false.
+.sp
+Use of \fIauto_fast_armor = true\fP requires properly configured PKINIT and
+WELLKNOWN/ANONYMOUS principal defined on the KDC side. Consult KDC documentation
+for details.
+.TP
\fBv4_instance_convert\fP
This subsection allows the administrator to configure exceptions
to the \fBdefault_domain\fP mapping rule. It contains V4 instances
--
2.51.0

View file

@ -1,40 +0,0 @@
From ff580d9cf86202d45454a6b6f53accc22cb40b62 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Sun, 19 Oct 2025 18:14:29 +0300
Subject: [PATCH] bail if prompter is not specified but required
GSSAPI gss_init_sec_context() may trigger credential re-initialization
if the cred in ccache is expired. If automatic FAST armor is in use,
we'd request Anonymous PKINIT and use it as an armor and this will
enable seeing pre-authentication methods which require armor presence.
OTP is one of such methods and its use requires prompter to be set,
but GSSAPI cannot specify a prompter and thus we should fail any
pre-auth where a prompter wasn't passed.
PKINIT PKCS11 and SAM-2 preauth methods use KRB5_LIBOS_CANTREADPWD while PKINIT
and gic_pwd.c use EIO. Use EIO here because we technically attempt to read a
PIN rather than a password.
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
---
src/lib/krb5/krb/preauth_otp.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/lib/krb5/krb/preauth_otp.c b/src/lib/krb5/krb/preauth_otp.c
index 07ffc15c2..48003da62 100644
--- a/src/lib/krb5/krb/preauth_otp.c
+++ b/src/lib/krb5/krb/preauth_otp.c
@@ -479,6 +479,9 @@ doprompt(krb5_context context, krb5_prompter_fct prompter, void *prompter_data,
krb5_error_code retval;
krb5_prompt_type prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
+ if (prompter == NULL)
+ return EIO;
+
if (prompttxt == NULL || out == NULL)
return EINVAL;
--
2.51.0

View file

@ -0,0 +1,220 @@
From 3a99832252755cf7e5fef2bd824459cea3eb823e 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)
---
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 63e67a2ba..c26dde535 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 bd0284afa..96e0931a2 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 2d9d56530..adbfa332b 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -489,6 +489,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 4953907aa..60b8dd311 100644
--- a/src/lib/krb5_32.def
+++ b/src/lib/krb5_32.def
@@ -503,3 +503,7 @@ EXPORTS
; new in 1.19
k5_cc_store_primary_cred @470 ; PRIVATE
k5_kt_have_match @471 ; PRIVATE GSSAPI
+
+; new in 1.20
+ krb5_marshal_credentials @472
+ krb5_unmarshal_credentials @473

View file

@ -0,0 +1,358 @@
From 8772d8f47b7460a0eef48366881483fd9b3acfd3 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)
---
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 9093f894d..772928e4d 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])

View file

@ -0,0 +1,84 @@
From e88f0319427cee7245fb05c97a25473297c9d2d6 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 15 Jan 2021 14:43:34 -0500
Subject: [PATCH] Add hostname canonicalization helper to k5test.py
To facilitate fallback tests, add a canonicalize_hostname() function
to k5test.py which works similarly to krb5_expand_hostname(). Use it
in t_gssapi.py for the recently-added acceptor name fallback test.
(cherry picked from commit 225fffe4e912772acea3a01d45bafb60bfb80948)
---
src/tests/gssapi/t_gssapi.py | 11 +++--------
src/util/k5test.py | 22 ++++++++++++++++++++++
2 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
index 1af6f31c2..e22cec427 100755
--- a/src/tests/gssapi/t_gssapi.py
+++ b/src/tests/gssapi/t_gssapi.py
@@ -8,7 +8,7 @@ for realm in multipass_realms():
realm.run(['./t_iov', '-s', 'p:' + realm.host_princ])
realm.run(['./t_pcontok', 'p:' + realm.host_princ])
-realm = K5Realm(krb5_conf={'libdefaults': {'rdns': 'false'}})
+realm = K5Realm()
# Test gss_add_cred().
realm.run(['./t_add_cred'])
@@ -62,13 +62,8 @@ realm.run(['./t_accname', 'p:host/-nomatch-',
expected_msg=' not found in keytab')
# If possible, test with an acceptor name requiring fallback to match
-# against a keytab entry. Forward-canonicalize the hostname, relying
-# on the rdns=false realm setting.
-try:
- ai = socket.getaddrinfo(hostname, None, 0, 0, 0, socket.AI_CANONNAME)
- (family, socktype, proto, canonname, sockaddr) = ai[0]
-except socket.gaierror:
- canonname = hostname
+# against a keytab entry.
+canonname = canonicalize_hostname(hostname)
if canonname != hostname:
os.rename(realm.keytab, realm.keytab + '.save')
canonprinc = 'host/' + canonname
diff --git a/src/util/k5test.py b/src/util/k5test.py
index 789b0f4b9..251d11a9d 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -155,6 +155,10 @@ Scripts may use the following functions and variables:
* password(name): Return a weakly random password based on name. The
password will be consistent across calls with the same name.
+* canonicalize_hostname(name, rdns=True): Return the DNS
+ canonicalization of name, optionally using reverse DNS. On error,
+ return name converted to lowercase.
+
* stop_daemon(proc): Stop a daemon process started with
realm.start_server() or realm.start_in_inetd(). Only necessary if
the port needs to be reused; daemon processes will be stopped
@@ -458,6 +462,24 @@ def password(name):
return name + str(os.getpid())
+def canonicalize_hostname(name, rdns=True):
+ """Canonicalize name using DNS, optionally with reverse DNS."""
+ try:
+ ai = socket.getaddrinfo(name, None, 0, 0, 0, socket.AI_CANONNAME)
+ except socket.gaierror as e:
+ return name.lower()
+ (family, socktype, proto, canonname, sockaddr) = ai[0]
+
+ if not rdns:
+ return canonname.lower()
+
+ try:
+ rname = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
+ except socket.gaierror:
+ return canonname.lower()
+ return rname[0].lower()
+
+
# Exit handler which ensures processes are cleaned up and, on failure,
# prints messages to help developers debug the problem.
def _onexit():

View file

@ -0,0 +1,60 @@
From fb4d9fa851b1d0d3375556d1cdc1fce72176df1e Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Thu, 3 Jun 2021 16:03:07 -0400
Subject: [PATCH] Allow kinit with keytab to defer canonicalization
[ghudson@mit.edu: added tests]
ticket: 9012 (new)
(cherry picked from commit 5e6a6efc5df689d9fb8730d0227167ffbb6ece0e)
---
src/clients/kinit/kinit.c | 11 -----------
src/tests/t_keytab.py | 13 +++++++++++++
2 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
index d1f5d74c3..5a6d7237c 100644
--- a/src/clients/kinit/kinit.c
+++ b/src/clients/kinit/kinit.c
@@ -510,17 +510,6 @@ k5_begin(struct k_opts *opts, struct k5_data *k5)
_("when creating default server principal name"));
goto cleanup;
}
- if (k5->me->realm.data[0] == 0) {
- ret = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
- if (ret == 0) {
- com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
- _("(principal %s)"), k5->name);
- } else {
- com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
- _("for local services"));
- }
- goto cleanup;
- }
} else if (k5->out_cc != NULL) {
/* If the output ccache is initialized, use its principal. */
if (krb5_cc_get_principal(k5->ctx, k5->out_cc, &princ) == 0)
diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py
index 850375c92..a9adebb26 100755
--- a/src/tests/t_keytab.py
+++ b/src/tests/t_keytab.py
@@ -41,6 +41,19 @@ realm.kinit(realm.user_princ, flags=['-i'],
expected_msg='keytab specified, forcing -k')
realm.klist(realm.user_princ)
+# Test default principal for -k. This operation requires
+# canonicalization against the keytab in krb5_get_init_creds_keytab()
+# as the krb5_sname_to_principal() result won't have a realm. Try
+# with and without without fallback processing since the code paths
+# are different.
+mark('default principal for -k')
+realm.run([kinit, '-k'])
+realm.klist(realm.host_princ)
+no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}}
+no_canon = realm.special_env('no_canon', False, krb5_conf=no_canon_conf)
+realm.run([kinit, '-k'], env=no_canon)
+realm.klist(realm.host_princ)
+
# Test extracting keys with multiple key versions present.
mark('multi-kvno extract')
os.remove(realm.keytab)

View file

@ -0,0 +1,35 @@
From 95547c12b39e62df55cef05cae890302834b7f98 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 23 Jun 2021 16:57:39 -0400
Subject: [PATCH] Clean up context after failed open in libkdb5
If krb5_db_open() or krb5_db_create() fails, release the dal_handle,
as the caller is unlikely to call krb5_db_close() after a failure.
(cherry picked from commit 849b7056e703bd3724d909263769ce190db59acc)
---
src/lib/kdb/kdb5.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c
index 47e9b31a7..11e2430c4 100644
--- a/src/lib/kdb/kdb5.c
+++ b/src/lib/kdb/kdb5.c
@@ -675,6 +675,8 @@ krb5_db_open(krb5_context kcontext, char **db_args, int mode)
return status;
status = v->init_module(kcontext, section, db_args, mode);
free(section);
+ if (status)
+ (void)krb5_db_fini(kcontext);
return status;
}
@@ -702,6 +704,8 @@ krb5_db_create(krb5_context kcontext, char **db_args)
return status;
status = v->create(kcontext, section, db_args);
free(section);
+ if (status)
+ (void)krb5_db_fini(kcontext);
return status;
}

View file

@ -0,0 +1,193 @@
From 5e5ea8e8345c8b2f3254b0d346b8e0de0df3a696 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Wed, 26 May 2021 18:22:10 -0400
Subject: [PATCH] Clean up gssapi_krb5 ccache name functions
Modernize kg_get_ccache_name() and kg_get_ccache_name(). Drop
unnecessary use of const in kg_get_ccache_name() so that its return
value can be properly freed. Fixes some static analyzer false
positives.
(cherry picked from commit f573f7f8ee5269103a0492d6521a3242c5ffb63b)
---
src/lib/gssapi/krb5/gssapiP_krb5.h | 3 +-
src/lib/gssapi/krb5/gssapi_krb5.c | 47 ++++++++--------------
src/lib/gssapi/krb5/set_ccache.c | 64 ++++++++++++------------------
3 files changed, 42 insertions(+), 72 deletions(-)
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index fd7abbd77..88d41130a 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -380,8 +380,7 @@ OM_uint32 kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status);
OM_uint32 kg_caller_provided_ccache_name (OM_uint32 *minor_status,
int *out_caller_provided_name);
-OM_uint32 kg_get_ccache_name (OM_uint32 *minor_status,
- const char **out_name);
+OM_uint32 kg_get_ccache_name (OM_uint32 *minor_status, char **out_name);
OM_uint32 kg_set_ccache_name (OM_uint32 *minor_status,
const char *name);
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index 46aa9b7a5..9915a8bb5 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -253,46 +253,31 @@ kg_caller_provided_ccache_name (OM_uint32 *minor_status,
}
OM_uint32
-kg_get_ccache_name (OM_uint32 *minor_status, const char **out_name)
+kg_get_ccache_name(OM_uint32 *minor_status, char **out_name)
{
- const char *name = NULL;
- OM_uint32 err = 0;
char *kg_ccache_name;
+ const char *def_name;
+ OM_uint32 err;
+ krb5_context context;
+
+ *out_name = NULL;
kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
-
if (kg_ccache_name != NULL) {
- name = strdup(kg_ccache_name);
- if (name == NULL)
- err = ENOMEM;
+ *out_name = strdup(kg_ccache_name);
+ err = (*out_name == NULL) ? ENOMEM : 0;
} else {
- krb5_context context = NULL;
-
- /* Reset the context default ccache (see text above), and then
- retrieve it. */
+ /* Use the default ccache name. */
err = krb5_gss_init_context(&context);
- if (!err)
- err = krb5_cc_set_default_name (context, NULL);
- if (!err) {
- name = krb5_cc_default_name(context);
- if (name) {
- name = strdup(name);
- if (name == NULL)
- err = ENOMEM;
- }
- }
- if (err && context)
- save_error_info(err, context);
- if (context)
- krb5_free_context(context);
- }
-
- if (!err) {
- if (out_name) {
- *out_name = name;
- }
+ if (err)
+ goto cleanup;
+ def_name = krb5_cc_default_name(context);
+ *out_name = (def_name != NULL) ? strdup(def_name) : NULL;
+ err = (*out_name == NULL) ? ENOMEM : 0;
+ krb5_free_context(context);
}
+cleanup:
*minor_status = err;
return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
}
diff --git a/src/lib/gssapi/krb5/set_ccache.c b/src/lib/gssapi/krb5/set_ccache.c
index 8acf3ec90..91c3462be 100644
--- a/src/lib/gssapi/krb5/set_ccache.c
+++ b/src/lib/gssapi/krb5/set_ccache.c
@@ -26,7 +26,7 @@
/*
* Set ccache name used by gssapi, and optionally obtain old ccache
- * name. Caller should not free returned name.
+ * name. Caller must not free returned name.
*/
#include <string.h>
@@ -38,11 +38,9 @@ gss_krb5int_ccache_name(OM_uint32 *minor_status,
const gss_OID desired_object,
const gss_buffer_t value)
{
- char *old_name = NULL;
OM_uint32 err = 0;
- OM_uint32 minor = 0;
- char *gss_out_name;
struct krb5_gss_ccache_name_req *req;
+ char *old_name, *cur_name = NULL;
err = gss_krb5int_initialize_library();
if (err) {
@@ -57,45 +55,33 @@ gss_krb5int_ccache_name(OM_uint32 *minor_status,
req = (struct krb5_gss_ccache_name_req *)value->value;
- gss_out_name = k5_getspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
+ /* Our job is simple if the caller doesn't want the current name. */
+ if (req->out_name == NULL)
+ return kg_set_ccache_name(minor_status, req->name);
- if (req->out_name) {
- const char *tmp_name = NULL;
+ /* Fetch the current name and change it. */
+ kg_get_ccache_name(&err, &cur_name);
+ if (err)
+ goto cleanup;
+ kg_set_ccache_name(&err, req->name);
+ if (err)
+ goto cleanup;
- if (!err) {
- kg_get_ccache_name (&err, &tmp_name);
- }
- if (!err) {
- old_name = gss_out_name;
- gss_out_name = (char *)tmp_name;
- }
- }
- /* If out_name was NULL, we keep the same gss_out_name value, and
- don't free up any storage (leave old_name NULL). */
+ /* Store the current name in a thread-specific variable. Free that
+ * variable's previous contents. */
+ old_name = k5_getspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
+ err = k5_setspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, cur_name);
+ if (err)
+ goto cleanup;
+ free(old_name);
- if (!err)
- kg_set_ccache_name (&err, req->name);
-
- minor = k5_setspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, gss_out_name);
- if (minor) {
- /* Um. Now what? */
- if (err == 0) {
- err = minor;
- }
- free(gss_out_name);
- gss_out_name = NULL;
- }
-
- if (!err) {
- if (req->out_name) {
- *(req->out_name) = gss_out_name;
- }
- }
-
- if (old_name != NULL) {
- free (old_name);
- }
+ /* Give the caller an alias to the stored value. */
+ *req->out_name = cur_name;
+ cur_name = NULL;
+ err = 0;
+cleanup:
+ free(cur_name);
*minor_status = err;
return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
}

View file

@ -0,0 +1,103 @@
From 1528c264d0e1eebff34132c01f4f770f01f1d1c2 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)
---
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 772928e4d..1f81a2190 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);

View file

@ -0,0 +1,62 @@
From 43be8fba5301d08fc4d5ddef14f8ae3d9655b0ba 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)
---
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 23fcf13ea..18505cd3d 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);

View file

@ -0,0 +1,45 @@
From bb8fa495d00ccd931eec87a01b8920636cf7903e 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)
---
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 6d244ffd4..39a504ca1 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -207,6 +207,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);

View file

@ -0,0 +1,57 @@
From 7e4429640f69acdd5d4f9caa655c011d8bd736f0 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Sat, 29 May 2021 12:05:49 -0400
Subject: [PATCH] Fix k5tls module for OpenSSL 3
Starting in OpenSSL 3, connection termination without a close_notify
alert causes SSL_read() to return SSL_ERROR_SSL instead of
SSL_ERROR_SYSCALL. OpenSSL 3 also provides a new option
SSL_OP_IGNORE_UNEXPECTED_EOF which allows an application to explicitly
ignore possible truncation attacks and receive SSL_ERROR_ZERO_RETURN
instead.
Remove the call to SSL_CTX_get_options() since SSL_CTX_set_options()
doesn't clear existing options.
[ghudson@mit.edu: edited commit message and comment]
(cherry picked from commit aa9b4a2a64046afd2fab7cb49c346295874a5fb6)
---
src/plugins/tls/k5tls/openssl.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/plugins/tls/k5tls/openssl.c b/src/plugins/tls/k5tls/openssl.c
index 76a43b3cd..99fda7ffc 100644
--- a/src/plugins/tls/k5tls/openssl.c
+++ b/src/plugins/tls/k5tls/openssl.c
@@ -433,7 +433,7 @@ setup(krb5_context context, SOCKET fd, const char *servername,
char **anchors, k5_tls_handle *handle_out)
{
int e;
- long options;
+ long options = SSL_OP_NO_SSLv2;
SSL_CTX *ctx = NULL;
SSL *ssl = NULL;
k5_tls_handle handle = NULL;
@@ -448,8 +448,19 @@ setup(krb5_context context, SOCKET fd, const char *servername,
ctx = SSL_CTX_new(SSLv23_client_method());
if (ctx == NULL)
goto error;
- options = SSL_CTX_get_options(ctx);
- SSL_CTX_set_options(ctx, options | SSL_OP_NO_SSLv2);
+
+#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
+ /*
+ * For OpenSSL 3 and later, mark close_notify alerts as optional. We don't
+ * need to worry about truncation attacks because the protocols this module
+ * is used with (Kerberos and change-password) receive a single
+ * length-delimited message from the server. For prior versions of OpenSSL
+ * we check for SSL_ERROR_SYSCALL when reading instead (this error changes
+ * to SSL_ERROR_SSL in OpenSSL 3).
+ */
+ options |= SSL_OP_IGNORE_UNEXPECTED_EOF;
+#endif
+ SSL_CTX_set_options(ctx, options);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), 0);

View file

@ -0,0 +1,64 @@
From 2d2bb9a14613b3283dabdd40c3ee28e5b680cf93 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 7 Jun 2021 15:00:41 -0400
Subject: [PATCH] Fix kadmin -k with fallback or referral realm
kadmin -k produces a client principal name with
krb5_sname_to_principal(), but it gets converted to a string and back
due to the signature of kadm5_init_with_skey(), which loses track of
the name type, so no canonicalization is performed.
In libkadm5clnt initialization, recognize the important subset of this
case--an empty realm indicates either fallback processing or the
referral realm--and restore the host-based name type so that the
client principal can be canonicalized against the keytab.
ticket: 9013 (new)
(cherry picked from commit dcb79089276624d7ddf44e08d35bd6d7d7e557d2)
---
src/lib/kadm5/clnt/client_init.c | 7 +++++++
src/tests/t_kadmin.py | 12 ++++++++++++
2 files changed, 19 insertions(+)
diff --git a/src/lib/kadm5/clnt/client_init.c b/src/lib/kadm5/clnt/client_init.c
index aa1223bb3..0aaca701f 100644
--- a/src/lib/kadm5/clnt/client_init.c
+++ b/src/lib/kadm5/clnt/client_init.c
@@ -221,9 +221,16 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
return KADM5_MISSING_KRB5_CONF_PARAMS;
}
+ /*
+ * Parse the client name. If it has an empty realm, it is almost certainly
+ * a host-based principal using DNS fallback processing or the referral
+ * realm, so give it the appropriate name type for canonicalization.
+ */
code = krb5_parse_name(handle->context, client_name, &client);
if (code)
goto error;
+ if (init_type == INIT_SKEY && client->realm.length == 0)
+ client->type = KRB5_NT_SRV_HST;
/*
* Get credentials. Also does some fallbacks in case kadmin/fqdn
diff --git a/src/tests/t_kadmin.py b/src/tests/t_kadmin.py
index fe6a3cc2e..98453d92e 100644
--- a/src/tests/t_kadmin.py
+++ b/src/tests/t_kadmin.py
@@ -51,4 +51,16 @@ for i in range(200):
realm.run_kadmin(['addprinc', '-randkey', 'foo%d' % i])
realm.run_kadmin(['listprincs'], expected_msg='foo199')
+# Test kadmin -k with the default principal, with and without
+# fallback. This operation requires canonicalization against the
+# keytab in krb5_get_init_creds_keytab() as the
+# krb5_sname_to_principal() result won't have a realm. Try with and
+# without without fallback processing since the code paths are
+# different.
+mark('kadmin -k')
+realm.run([kadmin, '-k', 'getprinc', realm.host_princ])
+no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}}
+no_canon = realm.special_env('no_canon', False, krb5_conf=no_canon_conf)
+realm.run([kadmin, '-k', 'getprinc', realm.host_princ], env=no_canon)
+
success('kadmin and kpasswd tests')

View file

@ -0,0 +1,664 @@
From a14e0fd3c1d00ba625e6d9eb72829f31527c6ad8 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 23 Jun 2021 16:53:16 -0400
Subject: [PATCH] Fix leaks on error in kadm5 init functions
In the GENERIC_CHECK_HANDLE function, separate out the
version-checking logic so we can call it in the init functions before
allocating resources.
In the client and server library initialization functions, use a
single exit path after argument validation, and share the destruction
code with kadm5_destroy() via a helper.
(cherry picked from commit 552d7b7626450f963b8e37345c472420c842402c)
---
src/lib/kadm5/admin_internal.h | 39 ++++---
src/lib/kadm5/clnt/client_init.c | 174 +++++++++++-----------------
src/lib/kadm5/srv/server_init.c | 191 ++++++++++---------------------
3 files changed, 145 insertions(+), 259 deletions(-)
diff --git a/src/lib/kadm5/admin_internal.h b/src/lib/kadm5/admin_internal.h
index faf8e9c36..9be53883a 100644
--- a/src/lib/kadm5/admin_internal.h
+++ b/src/lib/kadm5/admin_internal.h
@@ -11,29 +11,32 @@
#define KADM5_SERVER_HANDLE_MAGIC 0x12345800
-#define GENERIC_CHECK_HANDLE(handle, old_api_version, new_api_version) \
+#define CHECK_VERSIONS(struct_version, api_version, old_api_err, new_api_err) \
{ \
- kadm5_server_handle_t srvr = \
- (kadm5_server_handle_t) handle; \
- \
- if (! srvr) \
- return KADM5_BAD_SERVER_HANDLE; \
- if (srvr->magic_number != KADM5_SERVER_HANDLE_MAGIC) \
- return KADM5_BAD_SERVER_HANDLE; \
- if ((srvr->struct_version & KADM5_MASK_BITS) != \
- KADM5_STRUCT_VERSION_MASK) \
+ if ((struct_version & KADM5_MASK_BITS) != KADM5_STRUCT_VERSION_MASK) \
return KADM5_BAD_STRUCT_VERSION; \
- if (srvr->struct_version < KADM5_STRUCT_VERSION_1) \
+ if (struct_version < KADM5_STRUCT_VERSION_1) \
return KADM5_OLD_STRUCT_VERSION; \
- if (srvr->struct_version > KADM5_STRUCT_VERSION_1) \
+ if (struct_version > KADM5_STRUCT_VERSION_1) \
return KADM5_NEW_STRUCT_VERSION; \
- if ((srvr->api_version & KADM5_MASK_BITS) != \
- KADM5_API_VERSION_MASK) \
+ if ((api_version & KADM5_MASK_BITS) != KADM5_API_VERSION_MASK) \
return KADM5_BAD_API_VERSION; \
- if (srvr->api_version < KADM5_API_VERSION_2) \
- return old_api_version; \
- if (srvr->api_version > KADM5_API_VERSION_4) \
- return new_api_version; \
+ if (api_version < KADM5_API_VERSION_2) \
+ return old_api_err; \
+ if (api_version > KADM5_API_VERSION_4) \
+ return new_api_err; \
+ }
+
+#define GENERIC_CHECK_HANDLE(handle, old_api_err, new_api_err) \
+ { \
+ kadm5_server_handle_t srvr = handle; \
+ \
+ if (srvr == NULL) \
+ return KADM5_BAD_SERVER_HANDLE; \
+ if (srvr->magic_number != KADM5_SERVER_HANDLE_MAGIC) \
+ return KADM5_BAD_SERVER_HANDLE; \
+ CHECK_VERSIONS(srvr->struct_version, srvr->api_version, \
+ old_api_err, new_api_err); \
}
/*
diff --git a/src/lib/kadm5/clnt/client_init.c b/src/lib/kadm5/clnt/client_init.c
index 0aaca701f..75614bb19 100644
--- a/src/lib/kadm5/clnt/client_init.c
+++ b/src/lib/kadm5/clnt/client_init.c
@@ -138,6 +138,36 @@ kadm5_init_with_skey(krb5_context context, char *client_name,
server_handle);
}
+static kadm5_ret_t
+free_handle(kadm5_server_handle_t handle)
+{
+ kadm5_ret_t ret = 0;
+ OM_uint32 minor_stat;
+ krb5_ccache ccache;
+
+ if (handle == NULL)
+ return 0;
+
+ if (handle->destroy_cache && handle->cache_name != NULL) {
+ ret = krb5_cc_resolve(handle->context, handle->cache_name, &ccache);
+ if (!ret)
+ ret = krb5_cc_destroy(handle->context, ccache);
+ }
+ free(handle->cache_name);
+ (void)gss_release_cred(&minor_stat, &handle->cred);
+ if (handle->clnt != NULL && handle->clnt->cl_auth != NULL)
+ AUTH_DESTROY(handle->clnt->cl_auth);
+ if (handle->clnt != NULL)
+ clnt_destroy(handle->clnt);
+ if (handle->client_socket != -1)
+ close(handle->client_socket);
+ free(handle->lhandle);
+ kadm5_free_config_params(handle->context, &handle->params);
+ free(handle);
+
+ return ret;
+}
+
static kadm5_ret_t
init_any(krb5_context context, char *client_name, enum init_type init_type,
char *pass, krb5_ccache ccache_in, char *service_name,
@@ -145,36 +175,34 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
krb5_ui_4 api_version, char **db_args, void **server_handle)
{
int fd = -1;
- OM_uint32 minor_stat;
krb5_boolean iprop_enable;
int port;
rpcprog_t rpc_prog;
rpcvers_t rpc_vers;
- krb5_ccache ccache;
krb5_principal client = NULL, server = NULL;
struct timeval timeout;
- kadm5_server_handle_t handle;
+ kadm5_server_handle_t handle = NULL;
kadm5_config_params params_local;
- int code = 0;
+ krb5_error_code code;
generic_ret r = { 0, 0 };
initialize_ovk_error_table();
initialize_ovku_error_table();
- if (! server_handle) {
+ if (server_handle == NULL || client_name == NULL)
return EINVAL;
- }
- if (! (handle = malloc(sizeof(*handle)))) {
- return ENOMEM;
- }
- memset(handle, 0, sizeof(*handle));
- if (! (handle->lhandle = malloc(sizeof(*handle)))) {
- free(handle);
- return ENOMEM;
- }
+ CHECK_VERSIONS(struct_version, api_version, KADM5_OLD_LIB_API_VERSION,
+ KADM5_NEW_LIB_API_VERSION);
+
+ handle = k5alloc(sizeof(*handle), &code);
+ if (handle == NULL)
+ goto cleanup;
+ handle->lhandle = k5alloc(sizeof(*handle), &code);
+ if (handle->lhandle == NULL)
+ goto cleanup;
handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
handle->struct_version = struct_version;
@@ -192,33 +220,20 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
handle->context = context;
- if(client_name == NULL) {
- free(handle);
- return EINVAL;
- }
-
- /*
- * Verify the version numbers before proceeding; we can't use
- * CHECK_HANDLE because not all fields are set yet.
- */
- GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
- KADM5_NEW_LIB_API_VERSION);
-
memset(&params_local, 0, sizeof(params_local));
- if ((code = kadm5_get_config_params(handle->context, 0,
- params_in, &handle->params))) {
- free(handle);
- return(code);
- }
+ code = kadm5_get_config_params(handle->context, 0, params_in,
+ &handle->params);
+ if (code)
+ goto cleanup;
#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
KADM5_CONFIG_ADMIN_SERVER | \
KADM5_CONFIG_KADMIND_PORT)
if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
- free(handle);
- return KADM5_MISSING_KRB5_CONF_PARAMS;
+ code = KADM5_MISSING_KRB5_CONF_PARAMS;
+ goto cleanup;
}
/*
@@ -228,7 +243,7 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
*/
code = krb5_parse_name(handle->context, client_name, &client);
if (code)
- goto error;
+ goto cleanup;
if (init_type == INIT_SKEY && client->realm.length == 0)
client->type = KRB5_NT_SRV_HST;
@@ -239,7 +254,7 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
code = get_init_creds(handle, client, init_type, pass, ccache_in,
service_name, handle->params.realm, &server);
if (code)
- goto error;
+ goto cleanup;
/* If the service_name and client_name are iprop-centric, use the iprop
* port and RPC identifiers. */
@@ -258,7 +273,7 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
code = connect_to_server(handle->params.admin_server, port, &fd);
if (code)
- goto error;
+ goto cleanup;
handle->clnt = clnttcp_create(NULL, rpc_prog, rpc_vers, &fd, 0, 0);
if (handle->clnt == NULL) {
@@ -266,7 +281,7 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
#ifdef DEBUG
clnt_pcreateerror("clnttcp_create");
#endif
- goto error;
+ goto cleanup;
}
/* Set a one-hour timeout. */
@@ -278,10 +293,6 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
handle->lhandle->clnt = handle->clnt;
handle->lhandle->client_socket = fd;
- /* now that handle->clnt is set, we can check the handle */
- if ((code = _kadm5_check_handle((void *) handle)))
- goto error;
-
/*
* The RPC connection is open; establish the GSS-API
* authentication context.
@@ -289,7 +300,7 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
code = setup_gss(handle, params_in,
(init_type == INIT_CREDS) ? client : NULL, server);
if (code)
- goto error;
+ goto cleanup;
/*
* Bypass the remainder of the code and return straight away
@@ -297,7 +308,8 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
*/
if (iprop_enable) {
code = 0;
- *server_handle = (void *) handle;
+ *server_handle = handle;
+ handle = NULL;
goto cleanup;
}
@@ -306,7 +318,7 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
#ifdef DEBUG
clnt_perror(handle->clnt, "init_2 null resp");
#endif
- goto error;
+ goto cleanup;
}
/* Drop down to v3 wire protocol if server does not support v4 */
if (r.code == KADM5_NEW_SERVER_API_VERSION &&
@@ -315,7 +327,7 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
memset(&r, 0, sizeof(generic_ret));
if (init_2(&handle->api_version, &r, handle->clnt)) {
code = KADM5_RPC_ERROR;
- goto error;
+ goto cleanup;
}
}
/* Drop down to v2 wire protocol if server does not support v3 */
@@ -325,47 +337,21 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
memset(&r, 0, sizeof(generic_ret));
if (init_2(&handle->api_version, &r, handle->clnt)) {
code = KADM5_RPC_ERROR;
- goto error;
+ goto cleanup;
}
}
if (r.code) {
code = r.code;
- goto error;
+ goto cleanup;
}
- *server_handle = (void *) handle;
-
- goto cleanup;
-
-error:
- /*
- * Note that it is illegal for this code to execute if "handle"
- * has not been allocated and initialized. I.e., don't use "goto
- * error" before the block of code at the top of the function
- * that allocates and initializes "handle".
- */
- if (handle->destroy_cache && handle->cache_name) {
- if (krb5_cc_resolve(handle->context,
- handle->cache_name, &ccache) == 0)
- (void) krb5_cc_destroy (handle->context, ccache);
- }
- if (handle->cache_name)
- free(handle->cache_name);
- (void)gss_release_cred(&minor_stat, &handle->cred);
- if(handle->clnt && handle->clnt->cl_auth)
- AUTH_DESTROY(handle->clnt->cl_auth);
- if(handle->clnt)
- clnt_destroy(handle->clnt);
- if (fd != -1)
- close(fd);
- free(handle->lhandle);
- kadm5_free_config_params(handle->context, &handle->params);
+ *server_handle = handle;
+ handle = NULL;
cleanup:
- krb5_free_principal(handle->context, client);
- krb5_free_principal(handle->context, server);
- if (code)
- free(handle);
+ krb5_free_principal(context, client);
+ krb5_free_principal(context, server);
+ (void)free_handle(handle);
return code;
}
@@ -695,38 +681,8 @@ rpc_auth(kadm5_server_handle_t handle, kadm5_config_params *params_in,
kadm5_ret_t
kadm5_destroy(void *server_handle)
{
- OM_uint32 minor_stat;
- krb5_ccache ccache = NULL;
- int code = KADM5_OK;
- kadm5_server_handle_t handle =
- (kadm5_server_handle_t) server_handle;
-
CHECK_HANDLE(server_handle);
-
- if (handle->destroy_cache && handle->cache_name) {
- if ((code = krb5_cc_resolve(handle->context,
- handle->cache_name, &ccache)) == 0)
- code = krb5_cc_destroy (handle->context, ccache);
- }
- if (handle->cache_name)
- free(handle->cache_name);
- if (handle->cred)
- (void)gss_release_cred(&minor_stat, &handle->cred);
- if (handle->clnt && handle->clnt->cl_auth)
- AUTH_DESTROY(handle->clnt->cl_auth);
- if (handle->clnt)
- clnt_destroy(handle->clnt);
- if (handle->client_socket != -1)
- close(handle->client_socket);
- if (handle->lhandle)
- free (handle->lhandle);
-
- kadm5_free_config_params(handle->context, &handle->params);
-
- handle->magic_number = 0;
- free(handle);
-
- return code;
+ return free_handle(server_handle);
}
/* not supported on client */
kadm5_ret_t kadm5_lock(void *server_handle)
diff --git a/src/lib/kadm5/srv/server_init.c b/src/lib/kadm5/srv/server_init.c
index 3adc4b57d..2c0d51efd 100644
--- a/src/lib/kadm5/srv/server_init.c
+++ b/src/lib/kadm5/srv/server_init.c
@@ -19,23 +19,6 @@
#include "osconf.h"
#include "iprop_hdr.h"
-/*
- * Function check_handle
- *
- * Purpose: Check a server handle and return a com_err code if it is
- * invalid or 0 if it is valid.
- *
- * Arguments:
- *
- * handle The server handle.
- */
-
-static int check_handle(void *handle)
-{
- CHECK_HANDLE(handle);
- return 0;
-}
-
static int dup_db_args(kadm5_server_handle_t handle, char **db_args)
{
int count = 0;
@@ -84,6 +67,23 @@ static void free_db_args(kadm5_server_handle_t handle)
}
}
+static void
+free_handle(kadm5_server_handle_t handle)
+{
+ if (handle == NULL)
+ return;
+
+ destroy_pwqual(handle);
+ k5_kadm5_hook_free_handles(handle->context, handle->hook_handles);
+ ulog_fini(handle->context);
+ krb5_db_fini(handle->context);
+ krb5_free_principal(handle->context, handle->current_caller);
+ kadm5_free_config_params(handle->context, &handle->params);
+ free(handle->lhandle);
+ free_db_args(handle);
+ free(handle);
+}
+
kadm5_ret_t kadm5_init_with_password(krb5_context context, char *client_name,
char *pass, char *service_name,
kadm5_config_params *params,
@@ -163,8 +163,8 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
char **db_args,
void **server_handle)
{
- int ret;
- kadm5_server_handle_t handle;
+ krb5_error_code ret;
+ kadm5_server_handle_t handle = NULL;
kadm5_config_params params_local; /* for v1 compat */
if (! server_handle)
@@ -173,17 +173,17 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
if (! client_name)
return EINVAL;
- if (! (handle = (kadm5_server_handle_t) malloc(sizeof *handle)))
- return ENOMEM;
- memset(handle, 0, sizeof(*handle));
+ CHECK_VERSIONS(struct_version, api_version, KADM5_OLD_SERVER_API_VERSION,
+ KADM5_NEW_SERVER_API_VERSION);
+
+ handle = k5alloc(sizeof(*handle), &ret);
+ if (handle == NULL)
+ goto cleanup;
+ handle->context = context;
ret = dup_db_args(handle, db_args);
- if (ret) {
- free(handle);
- return ret;
- }
-
- handle->context = context;
+ if (ret)
+ goto cleanup;
initialize_ovk_error_table();
initialize_ovku_error_table();
@@ -192,13 +192,6 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
handle->struct_version = struct_version;
handle->api_version = api_version;
- /*
- * Verify the version numbers before proceeding; we can't use
- * CHECK_HANDLE because not all fields are set yet.
- */
- GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION,
- KADM5_NEW_SERVER_API_VERSION);
-
/*
* Acquire relevant profile entries. Merge values
* in params_in with values from profile, based on
@@ -208,11 +201,8 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
ret = kadm5_get_config_params(handle->context, 1, params_in,
&handle->params);
- if (ret) {
- free_db_args(handle);
- free(handle);
- return(ret);
- }
+ if (ret)
+ goto cleanup;
#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_DBNAME | \
KADM5_CONFIG_ENCTYPE | \
@@ -226,132 +216,69 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
KADM5_CONFIG_IPROP_PORT)
if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
- kadm5_free_config_params(handle->context, &handle->params);
- free_db_args(handle);
- free(handle);
- return KADM5_MISSING_CONF_PARAMS;
+ ret = KADM5_MISSING_CONF_PARAMS;
+ goto cleanup;
}
if ((handle->params.mask & KADM5_CONFIG_IPROP_ENABLED) == KADM5_CONFIG_IPROP_ENABLED
&& handle->params.iprop_enabled) {
if ((handle->params.mask & IPROP_REQUIRED_PARAMS) != IPROP_REQUIRED_PARAMS) {
- kadm5_free_config_params(handle->context, &handle->params);
- free_db_args(handle);
- free(handle);
- return KADM5_MISSING_CONF_PARAMS;
+ ret = KADM5_MISSING_CONF_PARAMS;
+ goto cleanup;
}
}
ret = krb5_set_default_realm(handle->context, handle->params.realm);
- if (ret) {
- kadm5_free_config_params(handle->context, &handle->params);
- free_db_args(handle);
- free(handle);
- return ret;
- }
+ if (ret)
+ goto cleanup;
ret = krb5_db_open(handle->context, db_args,
KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
- if (ret) {
- kadm5_free_config_params(handle->context, &handle->params);
- free_db_args(handle);
- free(handle);
- return(ret);
- }
+ if (ret)
+ goto cleanup;
- if ((ret = krb5_parse_name(handle->context, client_name,
- &handle->current_caller))) {
- kadm5_free_config_params(handle->context, &handle->params);
- krb5_db_fini(handle->context);
- free_db_args(handle);
- free(handle);
- return ret;
- }
+ ret = krb5_parse_name(handle->context, client_name,
+ &handle->current_caller);
+ if (ret)
+ goto cleanup;
- if (! (handle->lhandle = malloc(sizeof(*handle)))) {
- kadm5_free_config_params(handle->context, &handle->params);
- krb5_db_fini(handle->context);
- free_db_args(handle);
- free(handle);
- return ENOMEM;
- }
+ handle->lhandle = k5alloc(sizeof(*handle), &ret);
+ if (handle->lhandle == NULL)
+ goto cleanup;
*handle->lhandle = *handle;
handle->lhandle->api_version = KADM5_API_VERSION_4;
handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
handle->lhandle->lhandle = handle->lhandle;
- /* can't check the handle until current_caller is set */
- ret = check_handle((void *) handle);
- if (ret) {
- kadm5_free_config_params(handle->context, &handle->params);
- free_db_args(handle);
- free(handle);
- return ret;
- }
-
ret = kdb_init_master(handle, handle->params.realm,
(handle->params.mask & KADM5_CONFIG_MKEY_FROM_KBD)
&& handle->params.mkey_from_kbd);
- if (ret) {
- kadm5_free_config_params(handle->context, &handle->params);
- krb5_db_fini(handle->context);
- free_db_args(handle);
- free(handle);
- return ret;
- }
+ if (ret)
+ goto cleanup;
ret = kdb_init_hist(handle, handle->params.realm);
- if (ret) {
- kadm5_free_config_params(handle->context, &handle->params);
- krb5_db_fini(handle->context);
- free_db_args(handle);
- free(handle);
- return ret;
- }
+ if (ret)
+ goto cleanup;
ret = k5_kadm5_hook_load(context,&handle->hook_handles);
- if (ret) {
- kadm5_free_config_params(handle->context, &handle->params);
- krb5_db_fini(handle->context);
- krb5_free_principal(handle->context, handle->current_caller);
- free_db_args(handle);
- free(handle);
- return ret;
- }
+ if (ret)
+ goto cleanup;
ret = init_pwqual(handle);
- if (ret) {
- kadm5_free_config_params(handle->context, &handle->params);
- k5_kadm5_hook_free_handles(context, handle->hook_handles);
- krb5_db_fini(handle->context);
- krb5_free_principal(handle->context, handle->current_caller);
- free_db_args(handle);
- free(handle);
- return ret;
- }
+ if (ret)
+ goto cleanup;
- *server_handle = (void *) handle;
+ *server_handle = handle;
+ handle = NULL;
- return KADM5_OK;
+cleanup:
+ free_handle(handle);
+ return ret;
}
kadm5_ret_t kadm5_destroy(void *server_handle)
{
- kadm5_server_handle_t handle = server_handle;
-
CHECK_HANDLE(server_handle);
-
- destroy_pwqual(handle);
-
- k5_kadm5_hook_free_handles(handle->context, handle->hook_handles);
- ulog_fini(handle->context);
- krb5_db_fini(handle->context);
- krb5_free_principal(handle->context, handle->current_caller);
- kadm5_free_config_params(handle->context, &handle->params);
- handle->magic_number = 0;
- free(handle->lhandle);
- free_db_args(handle);
- free(handle);
-
+ free_handle(server_handle);
return KADM5_OK;
}

View file

@ -0,0 +1,551 @@
From 391379bff864751262dbcedb897f2c2dd394345f Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Sat, 15 May 2021 17:35:25 -0400
Subject: [PATCH] Fix softpkcs11 build issues with openssl 3.0
EVP_PKEY_get0_RSA() has been modified to have const return type. Remove
its usages in favor of the EVP_PKEY interface. Also remove calls to
RSA_blinding_off(), which we don't need and would require a non-const
object. Similarly, remove RSA_set_method() calls that set a pre-existing
default.
Since softpkcs11 doesn't link against krb5 and can't use zap(), allocate
buffers with OPENSSL_malloc() so can use OPENSSL_clear_free().
Move several argument validation checks to the top of their functions.
Fix some incorrect/inconsistent log messages.
(cherry picked from commit 00de1aad7b3647b91017c7009b0bc65cd0c8b2e0)
---
src/tests/softpkcs11/main.c | 360 ++++++++++++++----------------------
1 file changed, 141 insertions(+), 219 deletions(-)
diff --git a/src/tests/softpkcs11/main.c b/src/tests/softpkcs11/main.c
index 1cccdfb43..caa537b68 100644
--- a/src/tests/softpkcs11/main.c
+++ b/src/tests/softpkcs11/main.c
@@ -375,10 +375,9 @@ add_st_object(void)
return NULL;
soft_token.object.objs = objs;
- o = malloc(sizeof(*o));
+ o = calloc(1, sizeof(*o));
if (o == NULL)
return NULL;
- memset(o, 0, sizeof(*o));
o->attrs = NULL;
o->num_attributes = 0;
o->object_handle = soft_token.object.num_objs;
@@ -424,7 +423,7 @@ add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
CK_ULONG modulus_bits = 0;
CK_BYTE *exponent = NULL;
size_t exponent_len = 0;
- RSA *rsa;
+ const RSA *rsa;
const BIGNUM *n, *e;
rsa = EVP_PKEY_get0_RSA(key);
@@ -445,8 +444,6 @@ add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
exponent, exponent_len);
- RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
-
free(modulus);
free(exponent);
}
@@ -679,10 +676,6 @@ add_certificate(char *label,
} else {
/* XXX verify keytype */
- if (key_type == CKK_RSA)
- RSA_set_method(EVP_PKEY_get0_RSA(o->u.private_key.key),
- RSA_PKCS1_OpenSSL());
-
if (X509_check_private_key(cert, o->u.private_key.key) != 1) {
EVP_PKEY_free(o->u.private_key.key);
o->u.private_key.key = NULL;
@@ -695,7 +688,7 @@ add_certificate(char *label,
}
ret = CKR_OK;
- out:
+out:
if (ret != CKR_OK) {
st_logf("something went wrong when adding cert!\n");
@@ -1224,8 +1217,6 @@ C_Login(CK_SESSION_HANDLE hSession,
}
/* XXX check keytype */
- RSA_set_method(EVP_PKEY_get0_RSA(o->u.private_key.key),
- RSA_PKCS1_OpenSSL());
if (X509_check_private_key(o->u.private_key.cert, o->u.private_key.key) != 1) {
EVP_PKEY_free(o->u.private_key.key);
@@ -1495,8 +1486,9 @@ C_Encrypt(CK_SESSION_HANDLE hSession,
struct st_object *o;
void *buffer = NULL;
CK_RV ret;
- RSA *rsa;
- int padding, len, buffer_len, padding_len;
+ size_t buffer_len = 0;
+ int padding;
+ EVP_PKEY_CTX *ctx = NULL;
st_logf("Encrypt\n");
@@ -1512,70 +1504,58 @@ C_Encrypt(CK_SESSION_HANDLE hSession,
return CKR_ARGUMENTS_BAD;
}
- rsa = EVP_PKEY_get0_RSA(o->u.public_key);
-
- if (rsa == NULL)
- return CKR_ARGUMENTS_BAD;
-
- RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
-
- buffer_len = RSA_size(rsa);
-
- buffer = malloc(buffer_len);
- if (buffer == NULL) {
- ret = CKR_DEVICE_MEMORY;
- goto out;
- }
-
- ret = CKR_OK;
- switch(state->encrypt_mechanism->mechanism) {
- case CKM_RSA_PKCS:
- padding = RSA_PKCS1_PADDING;
- padding_len = RSA_PKCS1_PADDING_SIZE;
- break;
- case CKM_RSA_X_509:
- padding = RSA_NO_PADDING;
- padding_len = 0;
- break;
- default:
- ret = CKR_FUNCTION_NOT_SUPPORTED;
- goto out;
- }
-
- if ((CK_ULONG)buffer_len + padding_len < ulDataLen) {
- ret = CKR_ARGUMENTS_BAD;
- goto out;
- }
-
if (pulEncryptedDataLen == NULL) {
st_logf("pulEncryptedDataLen NULL\n");
ret = CKR_ARGUMENTS_BAD;
goto out;
}
- if (pData == NULL_PTR) {
+ if (pData == NULL) {
st_logf("data NULL\n");
ret = CKR_ARGUMENTS_BAD;
goto out;
}
- len = RSA_public_encrypt(ulDataLen, pData, buffer, rsa, padding);
- if (len <= 0) {
+ switch(state->encrypt_mechanism->mechanism) {
+ case CKM_RSA_PKCS:
+ padding = RSA_PKCS1_PADDING;
+ break;
+ case CKM_RSA_X_509:
+ padding = RSA_NO_PADDING;
+ break;
+ default:
+ ret = CKR_FUNCTION_NOT_SUPPORTED;
+ goto out;
+ }
+
+ ctx = EVP_PKEY_CTX_new(o->u.public_key, NULL);
+ if (ctx == NULL || EVP_PKEY_encrypt_init(ctx) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
+ EVP_PKEY_encrypt(ctx, NULL, &buffer_len, pData, ulDataLen) <= 0) {
ret = CKR_DEVICE_ERROR;
goto out;
}
- if (len > buffer_len)
- abort();
- if (pEncryptedData != NULL_PTR)
- memcpy(pEncryptedData, buffer, len);
- *pulEncryptedDataLen = len;
-
- out:
- if (buffer) {
- memset(buffer, 0, buffer_len);
- free(buffer);
+ buffer = OPENSSL_malloc(buffer_len);
+ if (buffer == NULL) {
+ ret = CKR_DEVICE_MEMORY;
+ goto out;
}
+
+ if (EVP_PKEY_encrypt(ctx, buffer, &buffer_len, pData, ulDataLen) <= 0) {
+ ret = CKR_DEVICE_ERROR;
+ goto out;
+ }
+ st_logf("Encrypt done\n");
+
+ if (pEncryptedData != NULL)
+ memcpy(pEncryptedData, buffer, buffer_len);
+ *pulEncryptedDataLen = buffer_len;
+
+ ret = CKR_OK;
+out:
+ OPENSSL_clear_free(buffer, buffer_len);
+ EVP_PKEY_CTX_free(ctx);
return ret;
}
@@ -1646,8 +1626,9 @@ C_Decrypt(CK_SESSION_HANDLE hSession,
struct st_object *o;
void *buffer = NULL;
CK_RV ret;
- RSA *rsa;
- int padding, len, buffer_len, padding_len;
+ size_t buffer_len = 0;
+ int padding;
+ EVP_PKEY_CTX *ctx = NULL;
st_logf("Decrypt\n");
@@ -1663,41 +1644,6 @@ C_Decrypt(CK_SESSION_HANDLE hSession,
return CKR_ARGUMENTS_BAD;
}
- rsa = EVP_PKEY_get0_RSA(o->u.private_key.key);
-
- if (rsa == NULL)
- return CKR_ARGUMENTS_BAD;
-
- RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
-
- buffer_len = RSA_size(rsa);
-
- buffer = malloc(buffer_len);
- if (buffer == NULL) {
- ret = CKR_DEVICE_MEMORY;
- goto out;
- }
-
- ret = CKR_OK;
- switch(state->decrypt_mechanism->mechanism) {
- case CKM_RSA_PKCS:
- padding = RSA_PKCS1_PADDING;
- padding_len = RSA_PKCS1_PADDING_SIZE;
- break;
- case CKM_RSA_X_509:
- padding = RSA_NO_PADDING;
- padding_len = 0;
- break;
- default:
- ret = CKR_FUNCTION_NOT_SUPPORTED;
- goto out;
- }
-
- if ((CK_ULONG)buffer_len + padding_len < ulEncryptedDataLen) {
- ret = CKR_ARGUMENTS_BAD;
- goto out;
- }
-
if (pulDataLen == NULL) {
st_logf("pulDataLen NULL\n");
ret = CKR_ARGUMENTS_BAD;
@@ -1710,24 +1656,48 @@ C_Decrypt(CK_SESSION_HANDLE hSession,
goto out;
}
- len = RSA_private_decrypt(ulEncryptedDataLen, pEncryptedData, buffer,
- rsa, padding);
- if (len <= 0) {
+ switch(state->decrypt_mechanism->mechanism) {
+ case CKM_RSA_PKCS:
+ padding = RSA_PKCS1_PADDING;
+ break;
+ case CKM_RSA_X_509:
+ padding = RSA_NO_PADDING;
+ break;
+ default:
+ ret = CKR_FUNCTION_NOT_SUPPORTED;
+ goto out;
+ }
+
+ ctx = EVP_PKEY_CTX_new(o->u.private_key.key, NULL);
+ if (ctx == NULL || EVP_PKEY_decrypt_init(ctx) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
+ EVP_PKEY_decrypt(ctx, NULL, &buffer_len, pEncryptedData,
+ ulEncryptedDataLen) <= 0) {
ret = CKR_DEVICE_ERROR;
goto out;
}
- if (len > buffer_len)
- abort();
+
+ buffer = OPENSSL_malloc(buffer_len);
+ if (buffer == NULL) {
+ ret = CKR_DEVICE_MEMORY;
+ goto out;
+ }
+
+ if (EVP_PKEY_decrypt(ctx, buffer, &buffer_len, pEncryptedData,
+ ulEncryptedDataLen) <= 0) {
+ ret = CKR_DEVICE_ERROR;
+ goto out;
+ }
+ st_logf("Decrypt done\n");
if (pData != NULL_PTR)
- memcpy(pData, buffer, len);
- *pulDataLen = len;
+ memcpy(pData, buffer, buffer_len);
+ *pulDataLen = buffer_len;
- out:
- if (buffer) {
- memset(buffer, 0, buffer_len);
- free(buffer);
- }
+ ret = CKR_OK;
+out:
+ OPENSSL_clear_free(buffer, buffer_len);
+ EVP_PKEY_CTX_free(ctx);
return ret;
}
@@ -1806,8 +1776,9 @@ C_Sign(CK_SESSION_HANDLE hSession,
struct st_object *o;
void *buffer = NULL;
CK_RV ret;
- RSA *rsa;
- int padding, len, buffer_len, padding_len;
+ int padding;
+ size_t buffer_len = 0;
+ EVP_PKEY_CTX *ctx = NULL;
st_logf("Sign\n");
VERIFY_SESSION_HANDLE(hSession, &state);
@@ -1822,40 +1793,6 @@ C_Sign(CK_SESSION_HANDLE hSession,
return CKR_ARGUMENTS_BAD;
}
- rsa = EVP_PKEY_get0_RSA(o->u.private_key.key);
-
- if (rsa == NULL)
- return CKR_ARGUMENTS_BAD;
-
- RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
-
- buffer_len = RSA_size(rsa);
-
- buffer = malloc(buffer_len);
- if (buffer == NULL) {
- ret = CKR_DEVICE_MEMORY;
- goto out;
- }
-
- switch(state->sign_mechanism->mechanism) {
- case CKM_RSA_PKCS:
- padding = RSA_PKCS1_PADDING;
- padding_len = RSA_PKCS1_PADDING_SIZE;
- break;
- case CKM_RSA_X_509:
- padding = RSA_NO_PADDING;
- padding_len = 0;
- break;
- default:
- ret = CKR_FUNCTION_NOT_SUPPORTED;
- goto out;
- }
-
- if ((CK_ULONG)buffer_len < ulDataLen + padding_len) {
- ret = CKR_ARGUMENTS_BAD;
- goto out;
- }
-
if (pulSignatureLen == NULL) {
st_logf("signature len NULL\n");
ret = CKR_ARGUMENTS_BAD;
@@ -1868,26 +1805,46 @@ C_Sign(CK_SESSION_HANDLE hSession,
goto out;
}
- len = RSA_private_encrypt(ulDataLen, pData, buffer, rsa, padding);
- st_logf("private encrypt done\n");
- if (len <= 0) {
+ switch(state->sign_mechanism->mechanism) {
+ case CKM_RSA_PKCS:
+ padding = RSA_PKCS1_PADDING;
+ break;
+ case CKM_RSA_X_509:
+ padding = RSA_NO_PADDING;
+ break;
+ default:
+ ret = CKR_FUNCTION_NOT_SUPPORTED;
+ goto out;
+ }
+
+ ctx = EVP_PKEY_CTX_new(o->u.private_key.key, NULL);
+ if (ctx == NULL || EVP_PKEY_sign_init(ctx) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
+ EVP_PKEY_sign(ctx, NULL, &buffer_len, pData, ulDataLen) <= 0) {
ret = CKR_DEVICE_ERROR;
goto out;
}
- if (len > buffer_len)
- abort();
- if (pSignature != NULL_PTR)
- memcpy(pSignature, buffer, len);
- *pulSignatureLen = len;
+ buffer = OPENSSL_malloc(buffer_len);
+ if (buffer == NULL) {
+ ret = CKR_DEVICE_MEMORY;
+ goto out;
+ }
+
+ if (EVP_PKEY_sign(ctx, buffer, &buffer_len, pData, ulDataLen) <= 0) {
+ ret = CKR_DEVICE_ERROR;
+ goto out;
+ }
+ st_logf("Sign done\n");
+
+ if (pSignature != NULL)
+ memcpy(pSignature, buffer, buffer_len);
+ *pulSignatureLen = buffer_len;
ret = CKR_OK;
-
- out:
- if (buffer) {
- memset(buffer, 0, buffer_len);
- free(buffer);
- }
+out:
+ OPENSSL_clear_free(buffer, buffer_len);
+ EVP_PKEY_CTX_free(ctx);
return ret;
}
@@ -1951,10 +1908,9 @@ C_Verify(CK_SESSION_HANDLE hSession,
{
struct session_state *state;
struct st_object *o;
- void *buffer = NULL;
CK_RV ret;
- RSA *rsa;
- int padding, len, buffer_len;
+ int padding;
+ EVP_PKEY_CTX *ctx = NULL;
st_logf("Verify\n");
VERIFY_SESSION_HANDLE(hSession, &state);
@@ -1969,39 +1925,6 @@ C_Verify(CK_SESSION_HANDLE hSession,
return CKR_ARGUMENTS_BAD;
}
- rsa = EVP_PKEY_get0_RSA(o->u.public_key);
-
- if (rsa == NULL)
- return CKR_ARGUMENTS_BAD;
-
- RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
-
- buffer_len = RSA_size(rsa);
-
- buffer = malloc(buffer_len);
- if (buffer == NULL) {
- ret = CKR_DEVICE_MEMORY;
- goto out;
- }
-
- ret = CKR_OK;
- switch(state->verify_mechanism->mechanism) {
- case CKM_RSA_PKCS:
- padding = RSA_PKCS1_PADDING;
- break;
- case CKM_RSA_X_509:
- padding = RSA_NO_PADDING;
- break;
- default:
- ret = CKR_FUNCTION_NOT_SUPPORTED;
- goto out;
- }
-
- if ((CK_ULONG)buffer_len < ulDataLen) {
- ret = CKR_ARGUMENTS_BAD;
- goto out;
- }
-
if (pSignature == NULL) {
st_logf("signature NULL\n");
ret = CKR_ARGUMENTS_BAD;
@@ -2014,34 +1937,34 @@ C_Verify(CK_SESSION_HANDLE hSession,
goto out;
}
- len = RSA_public_decrypt(ulDataLen, pData, buffer, rsa, padding);
- st_logf("private encrypt done\n");
- if (len <= 0) {
+ switch(state->verify_mechanism->mechanism) {
+ case CKM_RSA_PKCS:
+ padding = RSA_PKCS1_PADDING;
+ break;
+ case CKM_RSA_X_509:
+ padding = RSA_NO_PADDING;
+ break;
+ default:
+ ret = CKR_FUNCTION_NOT_SUPPORTED;
+ goto out;
+ }
+
+ ctx = EVP_PKEY_CTX_new(o->u.public_key, NULL);
+ if (ctx == NULL || EVP_PKEY_verify_init(ctx) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
+ EVP_PKEY_verify(ctx, pSignature, ulSignatureLen, pData,
+ ulDataLen) <= 0) {
ret = CKR_DEVICE_ERROR;
goto out;
}
- if (len > buffer_len)
- abort();
+ st_logf("Verify done\n");
- if ((CK_ULONG)len != ulSignatureLen) {
- ret = CKR_GENERAL_ERROR;
- goto out;
- }
-
- if (memcmp(pSignature, buffer, len) != 0) {
- ret = CKR_GENERAL_ERROR;
- goto out;
- }
-
- out:
- if (buffer) {
- memset(buffer, 0, buffer_len);
- free(buffer);
- }
+ ret = CKR_OK;
+out:
+ EVP_PKEY_CTX_free(ctx);
return ret;
}
-
CK_RV
C_VerifyUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pPart,
@@ -2072,7 +1995,6 @@ C_GenerateRandom(CK_SESSION_HANDLE hSession,
return CKR_FUNCTION_NOT_SUPPORTED;
}
-
CK_FUNCTION_LIST funcs = {
{ 2, 11 },
C_Initialize,

View file

@ -0,0 +1,96 @@
From 0779309f52f4c05bb1f01f638261ef1b8ca82488 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 7 Jun 2021 13:27:29 -0400
Subject: [PATCH] Fix some principal realm canonicalization cases
The no_hostrealm and subst_defrealm flags in struct canonprinc were
only applied when dns_canonicalize_hostname=fallback; in the other
cases, the initial krb5_sname_to_principal() result is treated as
canonical. For no_hostrealm this limitation doesn't currently matter,
because all uses pass a principal with no realm as input. However,
subst_defrealm is used to convert the referral realm to the default
realm in krb5_get_init_creds_keytab(), krb5_cc_cache_match(), and
gss_acquire_cred() when it needs to check the desired name against a
specified ccache.
In k5_canonprinc(), if the input principal is a
krb5_sname_to_principal() result and fallback isn't in effect, apply
subst_defrealm. Document in os-proto.h that no_hostrealm doesn't
remove an existing realm and that krb5_sname_to_principal() may
already have looked one up.
ticket: 9011 (new)
(cherry picked from commit c077d0c6430c4ac163443aacc03d14d206a4cbb8)
---
src/lib/krb5/os/os-proto.h | 13 +++++++++----
src/lib/krb5/os/sn2princ.c | 24 +++++++++++++++++++++---
2 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
index 7d5e7978f..a985f2aec 100644
--- a/src/lib/krb5/os/os-proto.h
+++ b/src/lib/krb5/os/os-proto.h
@@ -85,10 +85,15 @@ struct sendto_callback_info {
/*
* Initialize with all zeros except for princ. Set no_hostrealm to disable
- * host-to-realm lookup, which ordinarily happens after canonicalizing the host
- * part. Set subst_defrealm to substitute the default realm for the referral
- * realm after realm lookup (this has no effect if no_hostrealm is set). Free
- * with free_canonprinc() when done.
+ * host-to-realm lookup, which ordinarily happens during fallback processing
+ * after canonicalizing the host part. Set subst_defrealm to substitute the
+ * default realm for the referral realm after realm lookup. Do not set both
+ * flags. Free with free_canonprinc() when done.
+ *
+ * no_hostrealm only applies if fallback processing is in use
+ * (dns_canonicalize_hostname = fallback). It will not remove the realm if
+ * krb5_sname_to_principal() already canonicalized the hostname and looked up a
+ * realm. subst_defrealm applies whether or not fallback processing is in use.
*/
struct canonprinc {
krb5_const_principal princ;
diff --git a/src/lib/krb5/os/sn2princ.c b/src/lib/krb5/os/sn2princ.c
index c99b7da17..93c155932 100644
--- a/src/lib/krb5/os/sn2princ.c
+++ b/src/lib/krb5/os/sn2princ.c
@@ -271,18 +271,36 @@ krb5_error_code
k5_canonprinc(krb5_context context, struct canonprinc *iter,
krb5_const_principal *princ_out)
{
+ krb5_error_code ret;
int step = ++iter->step;
*princ_out = NULL;
- /* If we're not doing fallback, the input principal is canonical. */
- if (context->dns_canonicalize_hostname != CANONHOST_FALLBACK ||
- iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2 ||
+ /* If the hostname isn't from krb5_sname_to_principal(), the input
+ * principal is canonical. */
+ if (iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2 ||
iter->princ->data[1].length == 0) {
*princ_out = (step == 1) ? iter->princ : NULL;
return 0;
}
+ /* If we're not doing fallback, the hostname is canonical, but we may need
+ * to substitute the default realm. */
+ if (context->dns_canonicalize_hostname != CANONHOST_FALLBACK) {
+ if (step > 1)
+ return 0;
+ iter->copy = *iter->princ;
+ if (iter->subst_defrealm && iter->copy.realm.length == 0) {
+ ret = krb5_get_default_realm(context, &iter->realm);
+ if (ret)
+ return ret;
+ iter->copy = *iter->princ;
+ iter->copy.realm = string2data(iter->realm);
+ }
+ *princ_out = &iter->copy;
+ return 0;
+ }
+
/* Canonicalize without DNS at step 1, with DNS at step 2. */
if (step > 2)
return 0;

View file

@ -0,0 +1,26 @@
From 32ee800fa31d3bbda660bb9270f9aa20718ab202 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)
---
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 1f81a2190..46705f1da 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);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,149 @@
From 0a2778833d2f04a29fe9d7122913abe42299044a Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Sat, 15 May 2021 18:04:58 -0400
Subject: [PATCH] Remove deprecated OpenSSL calls from softpkcs11
Rewrite add_pubkey_info() in terms of the EVP_PKEY interface. In this
process, fix its unchecked allocations and fail fast for non-RSA keys.
(cherry picked from commit d6bf42279675100e3e4fe7c6e08eef74d49624cb)
---
src/configure.ac | 1 +
src/tests/softpkcs11/main.c | 106 ++++++++++++++++++++++++------------
2 files changed, 72 insertions(+), 35 deletions(-)
diff --git a/src/configure.ac b/src/configure.ac
index ea708491b..477819091 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1118,6 +1118,7 @@ int i = 1;
])], k5_cv_openssl_version_okay=yes, k5_cv_openssl_version_okay=no)])
old_LIBS="$LIBS"
AC_CHECK_LIB(crypto, PKCS7_get_signer_info)
+ AC_CHECK_FUNCS(EVP_PKEY_get_bn_param)
LIBS="$old_LIBS"
fi
if test "$k5_cv_openssl_version_okay" = yes && (test "$enable_pkinit" = yes || test "$enable_pkinit" = try); then
diff --git a/src/tests/softpkcs11/main.c b/src/tests/softpkcs11/main.c
index caa537b68..86b4ef711 100644
--- a/src/tests/softpkcs11/main.c
+++ b/src/tests/softpkcs11/main.c
@@ -413,47 +413,83 @@ add_object_attribute(struct st_object *o,
return CKR_OK;
}
+#ifdef HAVE_EVP_PKEY_GET_BN_PARAM
+
+/* Declare owner pointers since EVP_PKEY_get_bn_param() gives us copies. */
+#define DECLARE_BIGNUM(name) BIGNUM *name = NULL
+#define RELEASE_BIGNUM(bn) BN_clear_free(bn)
static CK_RV
-add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
+get_bignums(EVP_PKEY *key, BIGNUM **n, BIGNUM **e)
{
- switch (key_type) {
- case CKK_RSA: {
- CK_BYTE *modulus = NULL;
- size_t modulus_len = 0;
- CK_ULONG modulus_bits = 0;
- CK_BYTE *exponent = NULL;
- size_t exponent_len = 0;
- const RSA *rsa;
- const BIGNUM *n, *e;
+ if (EVP_PKEY_get_bn_param(key, "n", n) == 0 ||
+ EVP_PKEY_get_bn_param(key, "e", e) == 0)
+ return CKR_DEVICE_ERROR;
- rsa = EVP_PKEY_get0_RSA(key);
- RSA_get0_key(rsa, &n, &e, NULL);
- modulus_bits = BN_num_bits(n);
-
- modulus_len = BN_num_bytes(n);
- modulus = malloc(modulus_len);
- BN_bn2bin(n, modulus);
-
- exponent_len = BN_num_bytes(e);
- exponent = malloc(exponent_len);
- BN_bn2bin(e, exponent);
-
- add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
- add_object_attribute(o, 0, CKA_MODULUS_BITS,
- &modulus_bits, sizeof(modulus_bits));
- add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
- exponent, exponent_len);
-
- free(modulus);
- free(exponent);
- }
- default:
- /* XXX */
- break;
- }
return CKR_OK;
}
+#else
+
+/* Declare const pointers since the old API gives us aliases. */
+#define DECLARE_BIGNUM(name) const BIGNUM *name
+#define RELEASE_BIGNUM(bn)
+static CK_RV
+get_bignums(EVP_PKEY *key, const BIGNUM **n, const BIGNUM **e)
+{
+ const RSA *rsa;
+
+ rsa = EVP_PKEY_get0_RSA(key);
+ RSA_get0_key(rsa, n, e, NULL);
+
+ return CKR_OK;
+}
+
+#endif
+
+static CK_RV
+add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
+{
+ CK_BYTE *modulus = NULL, *exponent = 0;
+ size_t modulus_len = 0, exponent_len = 0;
+ CK_ULONG modulus_bits = 0;
+ CK_RV ret;
+ DECLARE_BIGNUM(n);
+ DECLARE_BIGNUM(e);
+
+ if (key_type != CKK_RSA)
+ abort();
+
+ ret = get_bignums(key, &n, &e);
+ if (ret != CKR_OK)
+ goto done;
+
+ modulus_bits = BN_num_bits(n);
+ modulus_len = BN_num_bytes(n);
+ exponent_len = BN_num_bytes(e);
+
+ modulus = malloc(modulus_len);
+ exponent = malloc(exponent_len);
+ if (modulus == NULL || exponent == NULL) {
+ ret = CKR_DEVICE_MEMORY;
+ goto done;
+ }
+
+ BN_bn2bin(n, modulus);
+ BN_bn2bin(e, exponent);
+
+ add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
+ add_object_attribute(o, 0, CKA_MODULUS_BITS, &modulus_bits,
+ sizeof(modulus_bits));
+ add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT, exponent, exponent_len);
+
+ ret = CKR_OK;
+done:
+ free(modulus);
+ free(exponent);
+ RELEASE_BIGNUM(n);
+ RELEASE_BIGNUM(e);
+ return ret;
+}
static int
pem_callback(char *buf, int num, int w, void *key)

View file

@ -0,0 +1,578 @@
From 818a777822658d44ce647fe975011a5ea25e8250 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 15 Jan 2021 13:51:34 -0500
Subject: [PATCH] Support host-based GSS initiator names
When checking if we can get initial credentials in the GSS krb5 mech,
use krb5_kt_have_match() to support fallback iteration. When scanning
the ccache or getting initial credentials, rewrite cred->name->princ
to the canonical client name. When a name check is necessary (such as
when the caller specifies both a name and ccache), use a new internal
API k5_sname_compare() to support fallback iteration. Add fallback
iteration to krb5_cc_cache_match() to allow host-based names to be
canonicalized against the cache collection.
Create and store the matching principal for acceptor names in
acquire_accept_cred() so that it isn't affected by changes in
cred->name->princ during acquire_init_cred().
ticket: 8978 (new)
(cherry picked from commit c374ab40dd059a5938ffc0440d87457ac5da3a46)
---
src/include/k5-int.h | 9 +++
src/include/k5-trace.h | 3 +
src/lib/gssapi/krb5/accept_sec_context.c | 15 +---
src/lib/gssapi/krb5/acquire_cred.c | 89 ++++++++++++++----------
src/lib/gssapi/krb5/gssapiP_krb5.h | 1 +
src/lib/gssapi/krb5/rel_cred.c | 1 +
src/lib/krb5/ccache/cccursor.c | 57 +++++++++++----
src/lib/krb5/libkrb5.exports | 1 +
src/lib/krb5/os/sn2princ.c | 23 +++++-
src/lib/krb5_32.def | 1 +
src/tests/gssapi/t_client_keytab.py | 44 ++++++++++++
src/tests/gssapi/t_credstore.py | 32 +++++++++
12 files changed, 214 insertions(+), 62 deletions(-)
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index efb523689..46f2ce2d3 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -2411,4 +2411,13 @@ 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
+/*
+ * Like krb5_principal_compare(), but with canonicalization of sname if
+ * fallback is enabled. This function should be avoided if multiple matches
+ * are required, since repeated canonicalization is inefficient.
+ */
+krb5_boolean
+k5_sname_compare(krb5_context context, krb5_const_principal sname,
+ krb5_const_principal princ);
+
#endif /* _KRB5_INT_H */
diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
index b3e039dc8..79b5a7a85 100644
--- a/src/include/k5-trace.h
+++ b/src/include/k5-trace.h
@@ -105,6 +105,9 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
#endif /* DISABLE_TRACING */
+#define TRACE_CC_CACHE_MATCH(c, princ, ret) \
+ TRACE(c, "Matching {princ} in collection with result: {kerr}", \
+ princ, ret)
#define TRACE_CC_DESTROY(c, cache) \
TRACE(c, "Destroying ccache {ccache}", cache)
#define TRACE_CC_GEN_NEW(c, cache) \
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index fcf2c2152..a1d7e0d96 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -683,7 +683,6 @@ kg_accept_krb5(minor_status, context_handle,
krb5_flags ap_req_options = 0;
krb5_enctype negotiated_etype;
krb5_authdata_context ad_context = NULL;
- krb5_principal accprinc = NULL;
krb5_ap_req *request = NULL;
code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
@@ -849,17 +848,9 @@ kg_accept_krb5(minor_status, context_handle,
}
}
- if (!cred->default_identity) {
- if ((code = kg_acceptor_princ(context, cred->name, &accprinc))) {
- major_status = GSS_S_FAILURE;
- goto fail;
- }
- }
-
- code = krb5_rd_req_decoded(context, &auth_context, request, accprinc,
- cred->keytab, &ap_req_options, NULL);
-
- krb5_free_principal(context, accprinc);
+ code = krb5_rd_req_decoded(context, &auth_context, request,
+ cred->acceptor_mprinc, cred->keytab,
+ &ap_req_options, NULL);
if (code) {
major_status = GSS_S_FAILURE;
goto fail;
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index 632ee7def..e226a0269 100644
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -123,11 +123,11 @@ gss_krb5int_register_acceptor_identity(OM_uint32 *minor_status,
/* Try to verify that keytab contains at least one entry for name. Return 0 if
* it does, KRB5_KT_NOTFOUND if it doesn't, or another error as appropriate. */
static krb5_error_code
-check_keytab(krb5_context context, krb5_keytab kt, krb5_gss_name_t name)
+check_keytab(krb5_context context, krb5_keytab kt, krb5_gss_name_t name,
+ krb5_principal mprinc)
{
krb5_error_code code;
krb5_keytab_entry ent;
- krb5_principal accprinc = NULL;
char *princname;
if (name->service == NULL) {
@@ -141,21 +141,15 @@ check_keytab(krb5_context context, krb5_keytab kt, krb5_gss_name_t name)
if (kt->ops->start_seq_get == NULL)
return 0;
- /* Get the partial principal for the acceptor name. */
- code = kg_acceptor_princ(context, name, &accprinc);
- if (code)
- return code;
-
- /* Scan the keytab for host-based entries matching accprinc. */
- code = k5_kt_have_match(context, kt, accprinc);
+ /* Scan the keytab for host-based entries matching mprinc. */
+ code = k5_kt_have_match(context, kt, mprinc);
if (code == KRB5_KT_NOTFOUND) {
- if (krb5_unparse_name(context, accprinc, &princname) == 0) {
+ if (krb5_unparse_name(context, mprinc, &princname) == 0) {
k5_setmsg(context, code, _("No key table entry found matching %s"),
princname);
free(princname);
}
}
- krb5_free_principal(context, accprinc);
return code;
}
@@ -202,8 +196,14 @@ acquire_accept_cred(krb5_context context, OM_uint32 *minor_status,
}
if (cred->name != NULL) {
+ code = kg_acceptor_princ(context, cred->name, &cred->acceptor_mprinc);
+ if (code) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+
/* Make sure we have keys matching the desired name in the keytab. */
- code = check_keytab(context, kt, cred->name);
+ code = check_keytab(context, kt, cred->name, cred->acceptor_mprinc);
if (code) {
if (code == KRB5_KT_NOTFOUND) {
k5_change_error_message_code(context, code, KG_KEYTAB_NOMATCH);
@@ -324,7 +324,6 @@ static krb5_boolean
can_get_initial_creds(krb5_context context, krb5_gss_cred_id_rec *cred)
{
krb5_error_code code;
- krb5_keytab_entry entry;
if (cred->password != NULL)
return TRUE;
@@ -336,20 +335,21 @@ can_get_initial_creds(krb5_context context, krb5_gss_cred_id_rec *cred)
if (cred->name == NULL)
return !krb5_kt_have_content(context, cred->client_keytab);
- /* Check if we have a keytab key for the client principal. */
- code = krb5_kt_get_entry(context, cred->client_keytab, cred->name->princ,
- 0, 0, &entry);
- if (code) {
- krb5_clear_error_message(context);
- return FALSE;
- }
- krb5_free_keytab_entry_contents(context, &entry);
- return TRUE;
+ /*
+ * Check if we have a keytab key for the client principal. This is a bit
+ * more permissive than we really want because krb5_kt_have_match()
+ * supports wildcarding and obeys ignore_acceptor_hostname, but that should
+ * generally be harmless.
+ */
+ code = k5_kt_have_match(context, cred->client_keytab, cred->name->princ);
+ return code == 0;
}
-/* Scan cred->ccache for name, expiry time, impersonator, refresh time. */
+/* Scan cred->ccache for name, expiry time, impersonator, refresh time. If
+ * check_name is true, verify the cache name against the credential name. */
static krb5_error_code
-scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred)
+scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred,
+ krb5_boolean check_name)
{
krb5_error_code code;
krb5_ccache ccache = cred->ccache;
@@ -365,23 +365,31 @@ scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred)
if (code)
return code;
- /* Credentials cache principal must match the initiator name. */
code = krb5_cc_get_principal(context, ccache, &ccache_princ);
if (code != 0)
goto cleanup;
- if (cred->name != NULL &&
- !krb5_principal_compare(context, ccache_princ, cred->name->princ)) {
- code = KG_CCACHE_NOMATCH;
- goto cleanup;
- }
- /* Save the ccache principal as the credential name if not already set. */
- if (!cred->name) {
+ if (cred->name == NULL) {
+ /* Save the ccache principal as the credential name. */
code = kg_init_name(context, ccache_princ, NULL, NULL, NULL,
KG_INIT_NAME_NO_COPY, &cred->name);
if (code)
goto cleanup;
ccache_princ = NULL;
+ } else {
+ /* Check against the desired name if needed. */
+ if (check_name) {
+ if (!k5_sname_compare(context, cred->name->princ, ccache_princ)) {
+ code = KG_CCACHE_NOMATCH;
+ goto cleanup;
+ }
+ }
+
+ /* Replace the credential name principal with the canonical client
+ * principal, retaining acceptor_mprinc if set. */
+ krb5_free_principal(context, cred->name->princ);
+ cred->name->princ = ccache_princ;
+ ccache_princ = NULL;
}
assert(cred->name->princ != NULL);
@@ -447,7 +455,7 @@ get_cache_for_name(krb5_context context, krb5_gss_cred_id_rec *cred)
assert(cred->name != NULL && cred->ccache == NULL);
#ifdef USE_LEASH
code = get_ccache_leash(context, cred->name->princ, &cred->ccache);
- return code ? code : scan_ccache(context, cred);
+ return code ? code : scan_ccache(context, cred, TRUE);
#else
/* Check first whether we can acquire tickets, to avoid overwriting the
* extended error message from krb5_cc_cache_match. */
@@ -456,7 +464,7 @@ get_cache_for_name(krb5_context context, krb5_gss_cred_id_rec *cred)
/* Look for an existing cache for the client principal. */
code = krb5_cc_cache_match(context, cred->name->princ, &cred->ccache);
if (code == 0)
- return scan_ccache(context, cred);
+ return scan_ccache(context, cred, FALSE);
if (code != KRB5_CC_NOTFOUND || !can_get)
return code;
krb5_clear_error_message(context);
@@ -633,6 +641,13 @@ get_initial_cred(krb5_context context, const struct verify_params *verify,
kg_cred_set_initial_refresh(context, cred, &creds.times);
cred->have_tgt = TRUE;
cred->expire = creds.times.endtime;
+
+ /* Steal the canonical client principal name from creds and save it in the
+ * credential name, retaining acceptor_mprinc if set. */
+ krb5_free_principal(context, cred->name->princ);
+ cred->name->princ = creds.client;
+ creds.client = NULL;
+
krb5_free_cred_contents(context, &creds);
cleanup:
krb5_get_init_creds_opt_free(context, opt);
@@ -721,7 +736,7 @@ acquire_init_cred(krb5_context context, OM_uint32 *minor_status,
if (cred->ccache != NULL) {
/* The caller specified a ccache; check what's in it. */
- code = scan_ccache(context, cred);
+ code = scan_ccache(context, cred, TRUE);
if (code == KRB5_FCC_NOFILE) {
/* See if we can get initial creds. If the caller didn't specify
* a name, pick one from the client keytab. */
@@ -984,7 +999,7 @@ kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
}
}
if (cred->ccache != NULL) {
- code = scan_ccache(context, cred);
+ code = scan_ccache(context, cred, FALSE);
if (code)
goto kerr;
}
@@ -996,7 +1011,7 @@ kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
code = krb5int_cc_default(context, &cred->ccache);
if (code)
goto kerr;
- code = scan_ccache(context, cred);
+ code = scan_ccache(context, cred, FALSE);
if (code == KRB5_FCC_NOFILE) {
/* Default ccache doesn't exist; fall through to client keytab. */
krb5_cc_close(context, cred->ccache);
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 3bacdcd35..fd7abbd77 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -175,6 +175,7 @@ typedef struct _krb5_gss_cred_id_rec {
/* name/type of credential */
gss_cred_usage_t usage;
krb5_gss_name_t name;
+ krb5_principal acceptor_mprinc;
krb5_principal impersonator;
unsigned int default_identity : 1;
unsigned int iakerb_mech : 1;
diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c
index a9515daf7..0da6c1b95 100644
--- a/src/lib/gssapi/krb5/rel_cred.c
+++ b/src/lib/gssapi/krb5/rel_cred.c
@@ -72,6 +72,7 @@ krb5_gss_release_cred(minor_status, cred_handle)
if (cred->name)
kg_release_name(context, &cred->name);
+ krb5_free_principal(context, cred->acceptor_mprinc);
krb5_free_principal(context, cred->impersonator);
if (cred->req_enctypes)
diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c
index 8f5872116..760216d05 100644
--- a/src/lib/krb5/ccache/cccursor.c
+++ b/src/lib/krb5/ccache/cccursor.c
@@ -30,6 +30,7 @@
#include "cc-int.h"
#include "../krb/int-proto.h"
+#include "../os/os-proto.h"
#include <assert.h>
@@ -141,18 +142,18 @@ krb5_cccol_cursor_free(krb5_context context,
return 0;
}
-krb5_error_code KRB5_CALLCONV
-krb5_cc_cache_match(krb5_context context, krb5_principal client,
- krb5_ccache *cache_out)
+static krb5_error_code
+match_caches(krb5_context context, krb5_const_principal client,
+ krb5_ccache *cache_out)
{
krb5_error_code ret;
krb5_cccol_cursor cursor;
krb5_ccache cache = NULL;
krb5_principal princ;
- char *name;
krb5_boolean eq;
*cache_out = NULL;
+
ret = krb5_cccol_cursor_new(context, &cursor);
if (ret)
return ret;
@@ -169,20 +170,52 @@ krb5_cc_cache_match(krb5_context context, krb5_principal client,
krb5_cc_close(context, cache);
}
krb5_cccol_cursor_free(context, &cursor);
+
if (ret)
return ret;
- if (cache == NULL) {
- ret = krb5_unparse_name(context, client, &name);
- if (ret == 0) {
- k5_setmsg(context, KRB5_CC_NOTFOUND,
+ if (cache == NULL)
+ return KRB5_CC_NOTFOUND;
+
+ *cache_out = cache;
+ return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_cache_match(krb5_context context, krb5_principal client,
+ krb5_ccache *cache_out)
+{
+ krb5_error_code ret;
+ struct canonprinc iter = { client, .subst_defrealm = TRUE };
+ krb5_const_principal canonprinc = NULL;
+ krb5_ccache cache = NULL;
+ char *name;
+
+ *cache_out = NULL;
+
+ while ((ret = k5_canonprinc(context, &iter, &canonprinc)) == 0 &&
+ canonprinc != NULL) {
+ ret = match_caches(context, canonprinc, &cache);
+ if (ret != KRB5_CC_NOTFOUND)
+ break;
+ }
+ free_canonprinc(&iter);
+
+ if (ret == 0 && canonprinc == NULL) {
+ ret = KRB5_CC_NOTFOUND;
+ if (krb5_unparse_name(context, client, &name) == 0) {
+ k5_setmsg(context, ret,
_("Can't find client principal %s in cache collection"),
name);
krb5_free_unparsed_name(context, name);
}
- ret = KRB5_CC_NOTFOUND;
- } else
- *cache_out = cache;
- return ret;
+ }
+
+ TRACE_CC_CACHE_MATCH(context, client, ret);
+ if (ret)
+ return ret;
+
+ *cache_out = cache;
+ return 0;
}
/* Store the error state for code from context into errsave, but only if code
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index adbfa332b..df6e2ffbe 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -181,6 +181,7 @@ k5_size_authdata_context
k5_size_context
k5_size_keyblock
k5_size_principal
+k5_sname_compare
k5_unmarshal_cred
k5_unmarshal_princ
k5_unwrap_cammac_svc
diff --git a/src/lib/krb5/os/sn2princ.c b/src/lib/krb5/os/sn2princ.c
index 8b7214189..c99b7da17 100644
--- a/src/lib/krb5/os/sn2princ.c
+++ b/src/lib/krb5/os/sn2princ.c
@@ -277,7 +277,8 @@ k5_canonprinc(krb5_context context, struct canonprinc *iter,
/* If we're not doing fallback, the input principal is canonical. */
if (context->dns_canonicalize_hostname != CANONHOST_FALLBACK ||
- iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2) {
+ iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2 ||
+ iter->princ->data[1].length == 0) {
*princ_out = (step == 1) ? iter->princ : NULL;
return 0;
}
@@ -288,6 +289,26 @@ k5_canonprinc(krb5_context context, struct canonprinc *iter,
return canonicalize_princ(context, iter, step == 2, princ_out);
}
+krb5_boolean
+k5_sname_compare(krb5_context context, krb5_const_principal sname,
+ krb5_const_principal princ)
+{
+ krb5_error_code ret;
+ struct canonprinc iter = { sname, .subst_defrealm = TRUE };
+ krb5_const_principal canonprinc = NULL;
+ krb5_boolean match = FALSE;
+
+ while ((ret = k5_canonprinc(context, &iter, &canonprinc)) == 0 &&
+ canonprinc != NULL) {
+ if (krb5_principal_compare(context, canonprinc, princ)) {
+ match = TRUE;
+ break;
+ }
+ }
+ free_canonprinc(&iter);
+ return match;
+}
+
krb5_error_code KRB5_CALLCONV
krb5_sname_to_principal(krb5_context context, const char *hostname,
const char *sname, krb5_int32 type,
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
index 60b8dd311..cf690dbe4 100644
--- a/src/lib/krb5_32.def
+++ b/src/lib/krb5_32.def
@@ -507,3 +507,4 @@ EXPORTS
; new in 1.20
krb5_marshal_credentials @472
krb5_unmarshal_credentials @473
+ k5_sname_compare @474 ; PRIVATE GSSAPI
diff --git a/src/tests/gssapi/t_client_keytab.py b/src/tests/gssapi/t_client_keytab.py
index 7847b3ecd..9a61d53b8 100755
--- a/src/tests/gssapi/t_client_keytab.py
+++ b/src/tests/gssapi/t_client_keytab.py
@@ -141,5 +141,49 @@ 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)
+realm.run([kdestroy, '-A'])
+
+# Test 19: host-based initiator name
+mark('host-based initiator name')
+hsvc = 'h:svc@' + hostname
+svcprinc = 'svc/%s@%s' % (hostname, realm.realm)
+realm.addprinc(svcprinc)
+realm.extract_keytab(svcprinc, realm.client_keytab)
+# On the first run we match against the keytab while getting tickets,
+# substituting the default realm.
+msgs = ('/Can\'t find client principal svc/%s@ in' % hostname,
+ 'Getting initial credentials for svc/%s@' % hostname,
+ 'Found entries for %s in keytab' % svcprinc,
+ 'Retrieving %s from FILE:%s' % (svcprinc, realm.client_keytab),
+ 'Storing %s -> %s in' % (svcprinc, realm.krbtgt_princ),
+ 'Retrieving %s -> %s from' % (svcprinc, realm.krbtgt_princ),
+ 'authenticator for %s -> %s' % (svcprinc, realm.host_princ))
+realm.run(['./t_ccselect', phost, hsvc], expected_trace=msgs)
+# On the second run we match against the collection.
+msgs = ('Matching svc/%s@ in collection with result: 0' % hostname,
+ 'Getting credentials %s -> %s' % (svcprinc, realm.host_princ),
+ 'authenticator for %s -> %s' % (svcprinc, realm.host_princ))
+realm.run(['./t_ccselect', phost, hsvc], expected_trace=msgs)
+realm.run([kdestroy, '-A'])
+
+# Test 20: host-based initiator name with fallback
+mark('host-based fallback initiator name')
+canonname = canonicalize_hostname(hostname)
+if canonname != hostname:
+ hfsvc = 'h:fsvc@' + hostname
+ canonprinc = 'fsvc/%s@%s' % (canonname, realm.realm)
+ realm.addprinc(canonprinc)
+ realm.extract_keytab(canonprinc, realm.client_keytab)
+ msgs = ('/Can\'t find client principal fsvc/%s@ in' % hostname,
+ 'Found entries for %s in keytab' % canonprinc,
+ 'authenticator for %s -> %s' % (canonprinc, realm.host_princ))
+ realm.run(['./t_ccselect', phost, hfsvc], expected_trace=msgs)
+ msgs = ('Matching fsvc/%s@ in collection with result: 0' % hostname,
+ 'Getting credentials %s -> %s' % (canonprinc, realm.host_princ))
+ realm.run(['./t_ccselect', phost, hfsvc], expected_trace=msgs)
+ realm.run([kdestroy, '-A'])
+else:
+ skipped('GSS initiator name fallback test',
+ '%s does not canonicalize to a different name' % hostname)
success('Client keytab tests')
diff --git a/src/tests/gssapi/t_credstore.py b/src/tests/gssapi/t_credstore.py
index c11975bf5..9be57bb82 100644
--- a/src/tests/gssapi/t_credstore.py
+++ b/src/tests/gssapi/t_credstore.py
@@ -15,6 +15,38 @@ msgs = ('Storing %s -> %s in %s' % (service_cs, realm.krbtgt_princ,
realm.run(['./t_credstore', '-s', 'p:' + service_cs, 'ccache', storagecache,
'keytab', servicekeytab], expected_trace=msgs)
+mark('matching')
+scc = 'FILE:' + os.path.join(realm.testdir, 'service_cache')
+realm.kinit(realm.host_princ, flags=['-k', '-c', scc])
+realm.run(['./t_credstore', '-i', 'p:' + realm.host_princ, 'ccache', scc])
+realm.run(['./t_credstore', '-i', 'h:host', 'ccache', scc])
+realm.run(['./t_credstore', '-i', 'h:host@' + hostname, 'ccache', scc])
+realm.run(['./t_credstore', '-i', 'p:wrong', 'ccache', scc],
+ expected_code=1, expected_msg='does not match desired name')
+realm.run(['./t_credstore', '-i', 'h:host@-nomatch-', 'ccache', scc],
+ expected_code=1, expected_msg='does not match desired name')
+realm.run(['./t_credstore', '-i', 'h:svc', 'ccache', scc],
+ expected_code=1, expected_msg='does not match desired name')
+
+mark('matching (fallback)')
+canonname = canonicalize_hostname(hostname)
+if canonname != hostname:
+ canonprinc = 'host/%s@%s' % (canonname, realm.realm)
+ realm.addprinc(canonprinc)
+ realm.extract_keytab(canonprinc, realm.keytab)
+ realm.kinit(canonprinc, flags=['-k', '-c', scc])
+ realm.run(['./t_credstore', '-i', 'h:host', 'ccache', scc])
+ realm.run(['./t_credstore', '-i', 'h:host@' + hostname, 'ccache', scc])
+ realm.run(['./t_credstore', '-i', 'h:host@' + canonname, 'ccache', scc])
+ realm.run(['./t_credstore', '-i', 'p:' + canonprinc, 'ccache', scc])
+ realm.run(['./t_credstore', '-i', 'p:' + realm.host_princ, 'ccache', scc],
+ expected_code=1, expected_msg='does not match desired name')
+ realm.run(['./t_credstore', '-i', 'h:host@-nomatch-', 'ccache', scc],
+ expected_code=1, expected_msg='does not match desired name')
+else:
+ skipped('fallback matching test',
+ '%s does not canonicalize to a different name' % hostname)
+
mark('rcache')
# t_credstore -r should produce a replay error normally, but not with
# rcache set to "none:".

View file

@ -0,0 +1,91 @@
From 8c055cea87da5d27dd4b039819e79508f68e14c6 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 a985f2aec..91d2791ce 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 0eedec175..c7f5d861a 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -802,11 +802,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);
@@ -850,8 +853,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

View file

@ -0,0 +1,235 @@
From 336f744403baa5dfaffcc5bd226fdd8f14a0200b 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)
---
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 46705f1da..23fcf13ea 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:')

View file

@ -0,0 +1,113 @@
From 9a34c4a2464f5c2df139967c9427d1dabb375d57 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Fri, 11 Mar 2022 11:33:56 +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 | 27 ++++++++++---------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 911e74fd9..3ceba8b0d 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,17 @@ 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,9 +1283,10 @@ 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
+ /* Some tokens can only do RSAEncryption without sha256 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 }
@@ -1304,7 +1305,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 +1334,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 +4148,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)
@@ -4621,10 +4622,10 @@ 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
+ * We'd like to use CKM_SHA256_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.
+ * always use CKM_RSA_PKCS and calculate the sha256 digest ourselves.
*/
id_cryptoctx->mech = CKM_RSA_PKCS;
@@ -4652,7 +4653,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

View file

@ -0,0 +1,22 @@
From 37e1fe755c6e976253a7f40ec7a9e740e4329789 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Mon, 21 Jun 2021 19:15:26 -0400
Subject: [PATCH] Use asan in one of the CI builds
(cherry picked from commit 7368354bcd0b58480a88b1fb81e63bd6aae7edf2)
---
.github/workflows/build.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8d1042b7b..06a35b7b9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -17,6 +17,7 @@ jobs:
os: ubuntu-18.04
compiler: clang
makevars: CPPFLAGS=-Werror
+ configureopts: --enable-asan
- name: linux-clang-openssl
os: ubuntu-18.04
compiler: clang

1
ci.fmf
View file

@ -1 +0,0 @@
resultsdb-testcase: separate

View file

@ -1,4 +1,4 @@
From 7b6453903c248a761d3ceb538dfacebbf3d3a9ff Mon Sep 17 00:00:00 2001
From 91e1d43858d90f59f5d9f45987cfca02c3175feb 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
@ -21,10 +21,10 @@ 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
---
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,10 +38,10 @@ 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 675175955..adba8238d 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:
@ -58,26 +58,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 +89,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 +102,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 +113,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 bc87c6f42..9bf407899 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 +126,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 +140,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 +151,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 +166,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 +178,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 +187,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 +328,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 +351,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 0143d155a..57672982f 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -39,6 +39,8 @@
@ -402,7 +397,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)
}
}
@ -421,7 +416,7 @@ index 7619563fc5..e123763954 100644
+
#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 +477,7 @@ index c597174b65..fc2d248001 100644
}
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
index 06ae751bc8..929f1cef67 100644
index a938665f6..7b5804b1d 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 +498,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 +512,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 +533,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 +555,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 +579,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 +591,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 +602,3 @@ index 1a772d450f..232e78bc05 100644
vt = (krb5_kdcpreauth_vtable)vtable;
vt->name = "spake";
vt->pa_type_list = pa_types;
--
2.45.1

View file

@ -1,4 +1,4 @@
From 30ff501e4b519396f5aea25e24919be817863e7c Mon Sep 17 00:00:00 2001
From 97966ffaac6bf9f2e09ac33a16b15794b31d51de 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,7 @@ 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
---
src/aclocal.m4 | 48 +++
src/build-tools/krb5-config.in | 3 +-
@ -63,13 +61,13 @@ 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 ca9fcf664..5afb96e58 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -85,6 +85,7 @@ AC_SUBST_FILE(libnodeps_frag)
@ -80,7 +78,7 @@ index ce3c5a9bac..3331970930 100644
KRB5_LIB_PARAMS
KRB5_AC_INITFINI
KRB5_AC_ENABLE_THREADS
@@ -1526,4 +1527,51 @@ AC_SUBST(PAM_LIBS)
@@ -1745,4 +1746,51 @@ AC_SUBST(PAM_LIBS)
AC_SUBST(PAM_MAN)
AC_SUBST(NON_PAM_MAN)
])dnl
@ -133,10 +131,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 dead0dddc..fef3e054f 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 +142,7 @@ index 8e6eb86601..7677f37359 100755
LIBS='@LIBS@'
GEN_LIB=@GEN_LIB@
@@ -253,7 +254,7 @@ if test -n "$do_libs"; then
@@ -254,7 +255,7 @@ if test -n "$do_libs"; then
fi
# If we ever support a flag to generate output suitable for static
@ -154,7 +152,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 3752174c7..0d2068575 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -177,6 +177,7 @@ LD = $(PURE) @LD@
@ -165,7 +163,7 @@ index a0c60c70b3..7eaa2f351c 100644
INSTALL=@INSTALL@
INSTALL_STRIP=
@@ -379,7 +380,7 @@ SUPPORT_LIB = -l$(SUPPORT_LIBNAME)
@@ -403,7 +404,7 @@ SUPPORT_LIB = -l$(SUPPORT_LIBNAME)
# HESIOD_LIBS is -lhesiod...
HESIOD_LIBS = @HESIOD_LIBS@
@ -175,10 +173,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 693f76a81..dd2cad3ee 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1401,6 +1401,8 @@ AC_PATH_PROG(GROFF, groff)
@@ -1391,6 +1391,8 @@ AC_PATH_PROG(GROFF, groff)
KRB5_WITH_PAM
@ -188,7 +186,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 cf524252f..efb523689 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -128,6 +128,7 @@ typedef unsigned char u_char;
@ -201,7 +199,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,10 +236,10 @@ index 0000000000..dfaaa847cb
+#endif
+#endif
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 4e09ed345d..09f800be52 100644
index 045334a08..db80063eb 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -83,6 +83,12 @@
@@ -87,6 +87,12 @@
#define THREEPARAMOPEN(x,y,z) open(x,y,z)
#endif
@ -255,7 +253,7 @@ index 4e09ed345d..09f800be52 100644
#include <stdlib.h>
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
index a89b5144f6..4d6cc0bdf9 100644
index 634ba4a8b..cea7939f4 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 +288,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 3be6dcb07..24d441e16 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 +301,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 498ca599a..c6b8efc28 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 +314,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 +331,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 +343,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 +353,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 +366,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 +416,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 e510211fc..f3ea28c8e 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 +437,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 +450,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 +463,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 1a476b586..b40bb2240 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 +478,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 +499,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 +520,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 +542,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 e87688d66..30f7c00ab 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 +579,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 +600,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 +622,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 +724,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 +862,7 @@ index 0000000000..807d039da3
+}
+
+static void
+pop_fscreatecon(char *previous)
+pop_fscreatecon(security_context_t previous)
+{
+ if (!is_selinux_enabled()) {
+ return;
@ -917,7 +916,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 +942,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 +963,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 +984,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 +1005,7 @@ index 0000000000..807d039da3
+{
+ int fd;
+ int errno_save;
+ char *ctx;
+ security_context_t ctx;
+ mode_t mode;
+ va_list ap;
+
@ -1033,6 +1032,3 @@ index 0000000000..807d039da3
+}
+
+#endif /* USE_SELINUX */
--
2.45.1

View file

@ -0,0 +1,752 @@
From 86d606e33439fd0511c5154be7f32b0df2c72e54 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Fri, 15 Nov 2019 20:05:16 +0000
Subject: [PATCH] [downstream] Use backported version of OpenSSL-3 KDF
interface
Last-updated: krb5-1.17
---
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 3e1052db7..ea708491b 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 e1153344e..911e74fd9 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. */

View file

@ -1,4 +1,4 @@
From 393830d96000ed692aa9a99ef87187d6f2863931 Mon Sep 17 00:00:00 2001
From 98b50683165089bf7bd9d91f953abbd79a8b1b08 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
@ -14,7 +14,7 @@ Last-updated: krb5-1.9
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 +27,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 +39,3 @@ index 8669c2436c..a22f23c02c 100644
install:
$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
--
2.45.1

View file

@ -1,4 +1,4 @@
From de4205c45e310ceaaa7cd7958af7293322fa43a6 Mon Sep 17 00:00:00 2001
From 659b3b4a654b879ce84ad8fb4621dde5ae693385 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
@ -30,10 +30,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 024d6370c..ca9fcf664 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -1458,3 +1458,72 @@ if test "$with_ldap" = yes; then
@@ -1677,3 +1677,72 @@ if test "$with_ldap" = yes; then
OPENLDAP_PLUGIN=yes
fi
])dnl
@ -107,7 +107,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,7 +145,7 @@ 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 af1286172..931f05404 100644
--- a/src/clients/ksu/main.c
+++ b/src/clients/ksu/main.c
@@ -26,6 +26,7 @@
@ -303,7 +303,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 +698,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 +760,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 4eb080784..693f76a81 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1399,6 +1399,8 @@ AC_SUBST([VERTO_VERSION])
@@ -1389,6 +1389,8 @@ AC_SUBST([VERTO_VERSION])
AC_PATH_PROG(GROFF, groff)
@ -772,6 +772,3 @@ index 77be7a2025..587221936e 100644
# Make localedir work in autoconf 2.5x.
if test "${localedir+set}" != set; then
localedir='$(datadir)/locale'
--
2.45.1

View file

@ -0,0 +1,24 @@
From 2d7e197fa88dccd3ca051f9f7cb97937c35c55a8 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
---
src/aclocal.m4 | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/aclocal.m4 b/src/aclocal.m4
index 5afb96e58..4a4d460e3 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -718,6 +718,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

View file

@ -1,8 +0,0 @@
--- !Policy
product_versions:
- fedora-*
decision_contexts:
- bodhi_update_push_stable
subject_type: koji_build
rules:
- !PassingTestCaseRule {test_case_name: fedora-ci.koji-build./plans/tests.functional}

View file

@ -1,7 +1,3 @@
[libdefaults]
# Allow RC4 HMAC-MD5 for session keys (see CVE-2022-37966)
#allow_rc4 = true
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88
@ -9,12 +5,10 @@
[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
}

View file

@ -0,0 +1,69 @@
From f35077bfc570205092eca2a9d44e50ce265622f4 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 03c613716..f309f1581 100644
--- a/src/lib/krad/attrset.c
+++ b/src/lib/krad/attrset.c
@@ -217,7 +217,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.1

209
krb5-krad-remote.patch Normal file
View file

@ -0,0 +1,209 @@
From ce160f8826bae223876a6527a731c36b6912db15 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 9 Nov 2021 13:00:43 -0500
Subject: [PATCH 1/2] 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 0143d155a..7619563fc 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -109,6 +109,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 7e491e994..06ae751bc 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.1
From e0084425df784952e76b3bcc8ae9d08300234733 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 8 Nov 2021 17:47:17 +0100
Subject: [PATCH 2/2] More python3 fixes for t_daemon.py
[ghudson@mit.edu: use a list comprehension instead of map()]
---
src/lib/krad/t_daemon.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/lib/krad/t_daemon.py b/src/lib/krad/t_daemon.py
index 7668cd7f8..4a3de079c 100755
--- a/src/lib/krad/t_daemon.py
+++ b/src/lib/krad/t_daemon.py
@@ -50,7 +50,7 @@ class TestServer(server.Server):
for key in pkt.keys():
if key == "User-Password":
- passwd = map(pkt.PwDecrypt, pkt[key])
+ passwd = [pkt.PwDecrypt(x) for x in pkt[key]]
reply = self.CreateReplyPacket(pkt)
if passwd == ['accept']:
@@ -61,8 +61,8 @@ class TestServer(server.Server):
srv = TestServer(addresses=["localhost"],
hosts={"127.0.0.1":
- server.RemoteHost("127.0.0.1", "foo", "localhost")},
- dict=dictionary.Dictionary(StringIO.StringIO(DICTIONARY)))
+ server.RemoteHost("127.0.0.1", b"foo", "localhost")},
+ dict=dictionary.Dictionary(StringIO(DICTIONARY)))
# Write a sentinel character to let the parent process know we're listening.
sys.stdout.write("~")
--
2.35.1

View file

@ -1,18 +0,0 @@
#!/bin/sh
set -e
export RPM_PACKAGE_NAME={{ name }}
export RPM_PACKAGE_VERSION={{ version }}
export RPM_PACKAGE_RELEASE={{ release }}
export RPM_ARCH={{ arch }}
export RPM_BUILD_NCPUS="$(getconf _NPROCESSORS_ONLN)"
testdir="$(mktemp -d)"
trap "rm -rf ${testdir}" EXIT
build_flags="$(eval "echo $(rpm --eval '%{_smp_mflags}')")"
mkdir "${testdir}/{{ name }}-tests"
cp -rp /usr/share/{{ name }}-tests/{{ arch }} "${testdir}/{{ name }}-tests/"
make -C "${testdir}/{{ name }}-tests/{{ arch }}/" $build_flags
keyctl session - make -C "${testdir}/{{ name }}-tests/{{ arch }}/" check

1213
krb5.spec

File diff suppressed because it is too large Load diff

View file

@ -1,5 +0,0 @@
summary: Tests
discover:
how: fmf
execute:
how: tmt

View file

@ -1,2 +1,2 @@
SHA512 (krb5-1.21.3.tar.gz) = 87bc06607f4d95ff604169cea22180703a42d667af05f66f1569b8bd592670c42820b335e5c279e8b4f066d1e7da20f1948a1e4def7c5d295c170cbfc7f49c71
SHA512 (krb5-1.21.3.tar.gz.asc) = 8992a5f5247315b9846aa73be4ee1ea223c0231a52d5c6c28718b1f3e3b45d62e2dad4aa5543a83163d1369bb79886b6c1c22766f22d8aa2f6b2575c54d0075c
SHA512 (krb5-1.19.2.tar.gz) = b90d6ed0e1e8a87eb5cb2c36d88b823a6a6caabf85e5d419adb8a930f7eea09a5f8491464e7e454cca7ba88be09d19415962fe0036ad2e31fc584f9fc0bbd470
SHA512 (krb5-1.19.2.tar.gz.asc) = 87c4d096dbb6821401125b8f8a315ce1aac029744ba9670a4f8a2a680e6dd5798e1c6d5d2b68b17fd9a4b3b9c6ff111cd1dcac42f934d48fb20381b3765e0f64

View file

@ -1,2 +0,0 @@
gef config gef.disable_color True
got-audit --all

View file

@ -1,12 +0,0 @@
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88
[realms]
${krb5REALM1} = {
#master_key_type = aes256-cts
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
}

View file

@ -1,29 +0,0 @@
# To opt out of the system crypto-policies configuration of krb5, remove the
# symlink at /etc/krb5.conf.d/crypto-policies which will not be recreated.
includedir /etc/krb5.conf.d/
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
default_realm = ${krb5REALM1}
dns_lookup_realm = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
rdns = false
default_ccache_name = KEYRING:persistent:%{uid}
[realms]
${krb5REALM1} = {
kdc = localhost.localdomain
admin_server = localhost.localdomain
}
[domain_realm]
${krb5HostName} = ${krb5REALM1}
[capaths]
${krb5REALM1} = .

View file

@ -1,12 +0,0 @@
summary: Audit the GOT for signs of tampering
description: |
Pointers in the server process GOT will be checked to ensure that
each function pointer's value is within a shared object file
that exports a symbol of that name, and that no shared object
files export conflicting symbols.
contact: Gordon Messmer <gordon.messmer@gmail.com>
require+:
- gdb-gef # needed to test got-audit
- krb5-server
test: ./runtest.sh
framework: beakerlib

View file

@ -1,121 +0,0 @@
#!/bin/bash
# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# runtest.sh of /CoreOS/openssh/Sanity/got-audit
# Description: Check pointers in the server process GOT for signs of tampering
# Author: Gordon Messmer <gordon.messmer@gmail.com>
#
# Include Beaker environment
. /usr/share/beakerlib/beakerlib.sh || exit 1
krb5REALM1='TEST1.REDHAT.COM'
krb5HostName=`hostname`
krb5DomainName=`hostname -d`
krb5User='alice'
krb5UserPass='alice'
krb5UserKrbPass='aaa'
krb5User2='bob'
krb5User3='carl'
krb5KDCPass='qwe'
krb5RootPass='rrr'
krb5conf="/etc/krb5.conf"
krb5confdir="/etc/krb5.conf.d"
krb5kdcconf="/var/kerberos/krb5kdc/kdc.conf"
krb5kadmacl="/var/kerberos/krb5kdc/kadm5.acl"
rlJournalStart
rlPhaseStartSetup
rlServiceStart sshd
rlRun "TestDir=\$(pwd)"
rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory"
rlRun "pushd $TmpDir"
rlRun "auditfile=\$(mktemp --tmpdir=${TmpDir})"
rlPhaseEnd
rlPhaseStartSetup "KDC and kadmind setup"
# Stop and backup
rlRun "rlServiceStop kadmin krb5kdc"
rlRun "rm -f /var/kerberos/krb5kdc/principal* /var/kerberos/krb5kdc/.k5*"
rlFileBackup $krb5conf /var/kerberos/krb5kdc /etc/sysconfig/{kadmin,krb5kdc} /etc/hosts
rlFileBackup --clean /root/.k5login
[ -e /etc/krb5.keytab ] && rlFileBackup /etc/krb5.keytab
[ -e $krb5confdir ] && rlFileBackup $krb5confdir
# Basic setup of KDC and krb5.conf
rlRun "sed -i \"s/\[libdefaults\]/[libdefaults]\n default_realm = $krb5REALM1/\" $krb5conf"
rlRun "sed -i \"s/\[realms\]/[realms]\n $krb5REALM1 = {\n kdc = $krb5HostName\n admin_server = $krb5HostName\n }/\" $krb5conf"
if [ "$krb5DomainName" ]; then
rlRun "sed -i \"s/\[domain_realm\]/[domain_realm]\n .$krb5DomainName = $krb5REALM1\n $krb5DomainName = $krb5REALM1/\" $krb5conf"
else
rlRun "sed -i \"s/\[domain_realm\]/[domain_realm]\n $krb5HostName = $krb5REALM1/\" $krb5conf"
fi
rlRun "sed -i s/EXAMPLE.COM/$krb5REALM1/ $krb5kdcconf"
# Configure the kadmin ACL
rlRun "echo \"*/master@$krb5REALM1 *\" > $krb5kadmacl"
if rlIsFedora '>=31';then
rlLog "Modify supported_enctypes for Fedora >=31. Remove *DES ciphers."
rlRun "sed -i \"s/supported_enctypes.*/supported_enctypes = aes256-cts:normal aes128-cts:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal/\" /var/kerberos/krb5kdc/kdc.conf"
elif rlIsRHEL '8' && [ `rpm -q --qf '%{VERSION}' krb5-server | cut -d"." -f2` -lt 18 ];then
rlLog "Modify supported_enctypes for RHEL-8."
rlRun "sed -i \"s/supported_enctypes.*/supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal/\" /var/kerberos/krb5kdc/kdc.conf"
else
#RHEL-8 Bug 1802334 - [Rebase] krb5: rebase to 1.18:
#- Removal of *DES encryption types
#https://bugzilla.redhat.com/show_bug.cgi?id=1802334
rlLog "Modify supported_enctypes for RHEL-8 with krb-1.18. Remove *DES ciphers."
rlRun "sed -i \"s/supported_enctypes.*/supported_enctypes = aes256-cts:normal aes128-cts:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal/\" /var/kerberos/krb5kdc/kdc.conf"
fi
# Create the realm databases
rlRun "rngd -r /dev/urandom"
rlRun "kdb5_util create -s -r $krb5REALM1 -P $krb5KDCPass"
rlRun "rlServiceStart kadmin krb5kdc"
rlRun "kadmin.local -r $krb5REALM1 -q \"addprinc -pw $krb5RootPass root/master\""
rlRun "kadmin.local -r $krb5REALM1 -q \"addprinc -pw $krb5UserKrbPass $krb5User\""
rlRun "kadmin.local -r $krb5REALM1 -q \"addprinc -randkey host/$krb5HostName\""
rlRun "kadmin.local -r $krb5REALM1 -q \"ktadd host/$krb5HostName\""
# Create test system user
[ $krb5User != "root" ] && rlRun "useradd $krb5User"
rlRun "echo $krb5UserPass | passwd --stdin $krb5User"
rlPhaseEnd
rlPhaseStartTest "Run GEF got-audit"
rlRun "systemctl restart krb5kdc.service"
rlRun "systemctl restart kadmin.service"
rlRun "systemctl --no-pager status krb5kdc.service"
rlRun "systemctl --no-pager status kadmin.service"
rlRun "SERVICE_PID=\$( systemctl show --property=MainPID krb5kdc.service | cut -f2 -d= )"
rlRun "echo SERVICE_PID is '$SERVICE_PID'"
[ -n "$SERVICE_PID" ] || rlFail "No service pid was found"
rlRun "gdb-gef --pid '$SERVICE_PID' --command='$TestDir'/got-audit.gdb --batch > '$auditfile'"
# Basic test: ensure that at least one symbol is found in libc.so,
# to verify that the report looks plausible.
rlAssertGrep " : /.*/libc.so" "$auditfile"
# Ensure the got-audit did not report any errors
rlAssertNotGrep " :: ERROR" "$auditfile"
rlRun "cp '$auditfile' '$TMT_TEST_DATA'/krb5kdc-got-audit.txt"
rlRun "SERVICE_PID=\$( systemctl show --property=MainPID kadmin.service | cut -f2 -d= )"
rlRun "echo SERVICE_PID is '$SERVICE_PID'"
[ -n "$SERVICE_PID" ] || rlFail "No service pid was found"
rlRun "gdb-gef --pid '$SERVICE_PID' --command='$TestDir'/got-audit.gdb --batch > '$auditfile'"
# Basic test: ensure that at least one symbol is found in libc.so,
# to verify that the report looks plausible.
rlAssertGrep " : /.*/libc.so" "$auditfile"
# Ensure the got-audit did not report any errors
rlAssertNotGrep " :: ERROR" "$auditfile"
rlRun "cp '$auditfile' '$TMT_TEST_DATA'/kadmin-got-audit.txt"
rlPhaseEnd
rlPhaseStartCleanup
rlRun "rm -rf /var/kerberos/krb5kdc/* /var/kerberos/krb5kdc/.k5* /etc/krb5* /etc/sysconfig/{kadmin,krb5kdc}"
rlFileRestore
rlServiceRestore krb5kdc kadmin
[ $krb5User != "root" ] && rlRun "userdel -r -f $krb5User"
rlRun "popd"
rlRun "rm -r $TmpDir" 0 "Removing tmp directory"
rlPhaseEnd
rlJournalPrintText
rlJournalEnd

View file

@ -27,6 +27,7 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Include Beaker environment
. /usr/bin/rhts-environment.sh
. /usr/share/beakerlib/beakerlib.sh || exit 1
PACKAGE="krb5"
@ -88,17 +89,11 @@ rlJournalStart
if rlIsRHEL 6; then
rlRun "sed -i \"s/EXAMPLE.COM/$krb5REALM1/\" $krb5conf"
rlRun "sed -i \"s/kerberos.example.com/$krb5HostName/\" $krb5conf"
if [ "$krb5DomainName" ]; then
rlRun "sed -i \"s/example.com/$krb5DomainName/\" $krb5conf"
fi
rlRun "sed -i \"s/example.com/$krb5DomainName/\" $krb5conf"
else
rlRun "sed -i \"s/\[libdefaults\]/[libdefaults]\n default_realm = $krb5REALM1/\" $krb5conf"
rlRun "sed -i \"s/\[realms\]/[realms]\n $krb5REALM1 = {\n kdc = $krb5HostName\n admin_server = $krb5HostName\n }/\" $krb5conf"
if [ "$krb5DomainName" ]; then
rlRun "sed -i \"s/\[domain_realm\]/[domain_realm]\n .$krb5DomainName = $krb5REALM1\n $krb5DomainName = $krb5REALM1/\" $krb5conf"
else
rlRun "sed -i \"s/\[domain_realm\]/[domain_realm]\n $krb5HostName = $krb5REALM1/\" $krb5conf"
fi
rlRun "sed -i \"s/\[domain_realm\]/[domain_realm]\n .$krb5DomainName = $krb5REALM1\n $krb5DomainName = $krb5REALM1/\" $krb5conf"
fi
rlRun "sed -i s/EXAMPLE.COM/$krb5REALM1/ $krb5kdcconf"
# Configure the kadmin ACL
@ -373,4 +368,4 @@ _EOF
rlRun "rm -r $TmpDir"
rlPhaseEnd
rlJournalPrintText
rlJournalEnd
rlJournalEnd

View file

@ -1,21 +0,0 @@
tag:
- CI-Tier-1
- CI-Tier-1-krb5
- Fedora 31
- Fedora 32
- FedoraReady
- IDM-CI-gating
- NoRHEL4
- NoRHEL5
- TIPpass
- TIPpass_Security
- Tier1
- Tier1security
- rhel_upgrade
tier: '1'
adjust:
- enabled: false
when: distro == rhel-4, rhel-5
continue: false
extra-nitrate: TC#0378369
extra-summary: /CoreOS/krb5/Sanity/inplace-upgrade-sanity-test

View file

@ -1,17 +0,0 @@
link:
- relates: https://bugzilla.redhat.com/show_bug.cgi?id=1394908
tag:
- NoRHEL4
- NoRHEL5
- TIPpass
- TIPpass_Security
- Tier2
tier: '2'
adjust:
- enabled: false
when: distro == rhel-4, rhel-5, rhel-6
continue: false
environment:
TEST_ENTROPY_SOURCE: yes
extra-nitrate: TC#0552039
extra-summary: 'BZ#1394908: Enable faster getrandom-based entropy system'

View file

@ -1,14 +0,0 @@
tag:
- Fedora 31
- Fedora 32
- FedoraReady
- NoRHEL4
- NoRHEL5
- rhel_upgrade
adjust:
- enabled: false
when: distro == rhel-4, rhel-5
continue: false
manual: true
extra-nitrate: TC#0608992
extra-summary: /CoreOS/krb5/Sanity/inplace-upgrade-sanity-test-manual

View file

@ -1,19 +0,0 @@
summary: Verifies basic scenarios which should work after inplace upgrade.
enabled: true
contact: Filip Dvorak <fdvorak@redhat.com>
component:
- krb5
test: ./runtest.sh
path: /tests/inplace-upgrade-sanity
framework: beakerlib
require:
- expect
- krb5-server
- krb5-workstation
- openssh-clients
- openssh-server
- rng-tools
- setools-console
duration: 20m
extra-summary: /CoreOS/krb5/Sanity/inplace-upgrade-sanity-test
extra-task: /CoreOS/krb5/Sanity/inplace-upgrade-sanity-test

16
tests/tests.yml Normal file
View file

@ -0,0 +1,16 @@
---
# This first play always runs on the local staging system
- hosts: localhost
roles:
- role: standard-test-beakerlib
tags:
- classic
tests:
- inplace-upgrade-sanity-test
required_packages:
- expect # Required for inplace-upgrade-sanity-test
- krb5-server # Required for inplace-upgrade-sanity-test
- krb5-workstation # Required for inplace-upgrade-sanity-test
- openssh-clients # Required for inplace-upgrade-sanity-test
- openssh-server # Required for inplace-upgrade-sanity-test
- rng-tools # Required for inplace-upgrade-sanity-test

View file

@ -1,7 +0,0 @@
summary: Run upstream tests
test: ./test.sh
enabled: true
path: /tests/upstream
require:
- krb5-tests
duration: 20m

View file

@ -1,7 +0,0 @@
#!/bin/sh -eux
rc=0
for test_exec in /usr/libexec/krb5-tests-*
do
"$test_exec" || rc=1
done
exit $rc