Compare commits

...
Sign in to create a new pull request.

104 commits

Author SHA1 Message Date
Julien Rische
c2ce5811ff krb5 1.21.3-11
- Fix strchr() conformance to C23
2026-01-05 14:29:38 +01:00
Alexander Bokovoy
fe6911cd3d Update prompter patch to the upstream version
Move the prompter patch to a separate one to avoid rebasing the
automated FAST one as it is context-dependent in the documentation area.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2025-10-20 10:34:09 +03:00
Alexander Bokovoy
53c3b9de3c Reject pre-authentication that requries a prompter if no prompter was provided
Resolves: rhbz#2403513

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2025-10-15 08:44:31 +03:00
Alexander Bokovoy
fb94528750 Test automated FAST channel acquisition during TGS-REQ
Upstream PR: https://github.com/krb5/krb5/pull/1447

It can be tested by using fedora-packager-kerberos from Rawhide
against Fedora KDC. If packagers have OTP tokens enabled, kinit will
automatically propose to enter password+OTP token value.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2025-09-26 14:34:06 +03:00
Fedora Release Engineering
a0a34794e3 Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild 2025-07-24 18:57:33 +00:00
Julien Rische
5c0a004494 krb5 1.21.3-6
- Do not block HMAC-MD4/5 in FIPS mode
  Resolves: rhbz#2370259
- PKINIT: implement paChecksum2 from MS-PKCA v20230920
  Resolves: rhbz#2357215
- Disallow RC4 HMAC-MD5 session keys by default (CVE-2025-3576)
  Resolves: rhbz#2359705

Signed-off-by: Julien Rische <jrische@redhat.com>
2025-06-06 13:01:37 +02:00
Julien Rische
f2bc777d63 krb5 1.21.3-5
- Prevent overflow when calculating ulog block size (CVE-2025-24528)
  Resolves: rhbz#2342798
- Support PKCS11 EC client certs in PKINIT
  Resolves: rhbz#2341962
- kdb5_util: fix DB entry flags on modification
  Resolves: rhbz#2336555
- Add ECDH support for PKINIT (RFC5349)
  Resolves: rhbz#2214326
- Remove dependency of krb5-libs on gawk and sed
  Resolves: rhbz#2323859

Signed-off-by: Julien Rische <jrische@redhat.com>
2025-01-29 19:32:00 +01:00
Fedora Release Engineering
099df268ce Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild 2025-01-17 09:48:45 +00:00
Julien Rische
9e0ac6c616 krb5 1.21.3-3
- libkrad: implement support for Message-Authenticator (CVE-2024-3596)
  Resolves: rhbz#2304071
- Fix various issues detected by static analysis
  Resolves: rhbz#2322704
- Remove RSA protocol for PKINIT
  Resolves: rhbz#2322706
- Make TCP waiting time configurable
  Resolves: rhbz#2322711

Signed-off-by: Julien Rische <jrische@redhat.com>
2024-10-30 12:49:36 +01:00
Gordon Messmer
4c1f565dfa Examine the server process GOT for signs of tampering. 2024-08-03 19:35:59 -07:00
Fedora Release Engineering
9767c1c24e Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild 2024-07-18 12:40:10 +00:00
Julien Rische
d71494ca6c krb5 1.21.3-1
- New upstream version (1.21.3)
- CVE-2024-26458: Memory leak in src/lib/rpc/pmap_rmt.c
  Resolves: rhbz#2266732
- CVE-2024-26461: Memory leak in src/lib/gssapi/krb5/k5sealv3.c
  Resolves: rhbz#2266741
- CVE-2024-26462: Memory leak in src/kdc/ndr.c
  Resolves: rhbz#2266743
- Add missing SPDX license identifiers
  Resolves: rhbz#2265333

Signed-off-by: Julien Rische <jrische@redhat.com>
2024-07-09 12:11:50 +02:00
Julien Rische
b45374269b krb5 1.21.2-6
- CVE-2024-37370 CVE-2024-37371: GSS message token handling
  Resolves: rhbz#2294678 rhbz#2294680
- Fix double free in klist's show_ccache()
  Resolves: rhbz#2257301
- Do not include files with "~" termination in krb5-tests

Signed-off-by: Julien Rische <jrische@redhat.com>
2024-07-08 15:09:03 +02:00
Fedora Release Engineering
5cc4a0d8bc Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild 2024-01-25 00:53:41 +00:00
Fedora Release Engineering
87d784ddd7 Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild 2024-01-21 02:56:15 +00:00
Julien Rische
1ed0e3a2d8 krb5 1.21.2-3
- Fix double free in klist's show_ccache()
  Resolves: rhbz#2257301
- Store krb5-tests files in architecture-specific directories
  Resolves: rhbz#2244601

Signed-off-by: Julien Rische <jrische@redhat.com>
2024-01-17 14:06:16 +01:00
Julien Rische
0fe5c327ec Fix memory leaks and use SPDX license expression
- Use SPDX expression for license tag
- Fix unimportant memory leaks
  Resolves: rhbz#2223274

Signed-off-by: Julien Rische <jrische@redhat.com>
2023-10-16 16:10:43 +02:00
Julien Rische
f5676fd233 New upstream version (1.21.2)
- Fix double-free in KDC TGS processing (CVE-2023-39975)
  Resolves: rhbz#2229113
- Make tests compatible with Python 3.12
  Resolves: rhbz#2224013

Signed-off-by: Julien Rische <jrische@redhat.com>
2023-08-16 11:30:37 +02:00
Fedora Release Engineering
ae2cf9bef3 Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2023-07-20 09:33:35 +00:00
Marek Blaha
a2c04215f0 Replace file dependency by package name
By default, dnf5 does not download the filelists repository metadata
required to resolve file dependencies outside of /usr/(s)bin or /etc.
This causes the krb5-server file to become uninstallable.

$ dnf5 install krb5-server
Repositories loaded.
Failed to resolve the transaction:
Problem: conflicting requests
  - nothing provides /usr/share/dict/words needed by krb5-server-1.21-1.fc39.x86_64

This change aligns with the Fedora packaging guidelines, as stated here:
https://docs.fedoraproject.org/en-US/packaging-guidelines/#_file_and_directory_dependencies

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2216903
2023-06-29 08:32:10 +02:00
Julien Rische
0b340d0ef3 New upstream version (1.21)
Do not disable PKINIT if some of the well-known DH groups are unavailable
  Resolves: rhbz#2214297
Make PKINIT CMS SHA-1 signature verification available in FIPS mode
  Resolves: rhbz#2214300
Allow to set PAC ticket signature as optional
  Resolves: rhbz#2181311
Add support for MS-PAC extended KDC signature (CVE-2022-37967)
  Resolves: rhbz#2166001
Fix syntax error in aclocal.m4
  Resolves: rhbz#2143306

Signed-off-by: Julien Rische <jrische@redhat.com>
2023-06-12 17:29:15 +02:00
Julien Rische
7058594eab Add support for MS-PAC extended KDC signature (CVE-2022-37967)
Resolves: rhbz#2166001
Signed-off-by: Julien Rische <jrische@redhat.com>
2023-01-31 17:56:02 +01:00
Julien Rische
ec957f5711 Do not block KRB5KDF and MD4/5 in FIPS mode
Bypass OpenSSL's restrictions to use KRB5KDF in FIPS mode in case at
least one of AES SHA-1 HMAC encryption types are used.

Use OpenSSL 3.0 library context to access MD4 and MD5 lazily from
legacy provider if RADIUS is being used or RC4 encryption type is
enabled, without affecting global context.

Such exceptions should not be allowed by the default FIPS crypto
policy.

Signed-off-by: Julien Rische <jrische@redhat.com>
2023-01-30 12:52:50 +01:00
Fedora Release Engineering
dca288bae2 Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2023-01-19 15:08:24 +00:00
Julien Rische
4a4fd39d5e Add AES SHA-2 HMAC family as default KDC etypes
Resolves: rhbz#2114771
Signed-off-by: Julien Rische <jrische@redhat.com>
2023-01-18 16:08:42 +01:00
Julien Rische
4eee9bbb50 Strip debugging data from ksu executable file
Signed-off-by: Julien Rische <jrische@redhat.com>
2023-01-18 16:08:41 +01:00
Julien Rische
f0b4f85e9e Include missing OpenSSL FIPS header
Signed-off-by: Julien Rische <jrische@redhat.com>
2023-01-09 13:28:16 +01:00
Julien Rische
f29ff7186e Make tests compatible with sssd_krb5_locator_plugin.so 2023-01-09 13:28:16 +01:00
Yaakov Selkowitz
ba968605e7 Fix openssl dependencies for RHEL/ELN 2022-12-07 19:18:54 -05:00
Julien Rische
f003c0755c Enable TMT integration with Fedora CI
Signed-off-by: Julien Rische <jrische@redhat.com>
2022-12-06 14:48:31 +01:00
Alexander Bokovoy
a206938c15 Bump KDB version to 9.0
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2022-12-01 17:57:01 +02:00
Julien Rische
95288a2fb9 Use TMT for gating tests
Signed-off-by: Julien Rische <jrische@redhat.com>
2022-12-01 15:16:23 +01:00
Julien Rische
3668746b8f Remove invalid password expiry warning
Resolves: rhbz#2129113
Signed-off-by: Julien Rische <jrische@redhat.com>
2022-11-24 11:35:42 +01:00
Julien Rische
603ad7099e Update error checking for OpenSSL CMS_verify
Resolves: rhbz#2119704
Signed-off-by: Julien Rische <jrische@redhat.com>
2022-11-24 11:35:26 +01:00
Julien Rische
56cee506e7 New upstream version (1.20.1)
Also set "supportedCMSTypes" to SHA-512/256 with RSA encryption

Resolves: rhbz#2124463
Resolves: rhbz#2114766
Signed-off-by: Julien Rische <jrische@redhat.com>
2022-11-24 11:35:10 +01:00
Julien Rische
c13bf943d8 Fix integer overflows in PAC parsing (CVE-2022-42898)
Resolves: rhbz#2143011
Signed-off-by: Julien Rische <jrische@redhat.com>
2022-11-16 10:35:01 +01:00
Andreas Schneider
0c2f5dcbe5 Add missing BR for resolv_wrapper to run t_discover_uri.py 2022-08-03 13:17:09 +02:00
Andreas Schneider
f5aa40a4a2 Do not define netlib, but use autoconf detection for res_* functions
This looks like an ancient patch and is not needed anymore.
2022-08-03 13:17:09 +02:00
Andreas Schneider
440331a1e4 Fix the Source0 and Source1 variables 2022-08-03 13:15:15 +02:00
Andreas Schneider
3907ec760c Use baserelease to set the release number 2022-08-02 12:13:54 +02:00
Fedora Release Engineering
e138eb8125 Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2022-07-21 16:36:11 +00:00
Julien Rische
601b89387b Read GSS configuration files with mtime 0
There is at least one case (with flatpaks) where configuration files
in the special read-only /etc all have an mtime of 0.  Using an
initial last modified time of 0 in g_initialize.c causes these files
to never be read.

Change the initial high value to the be the "invalid" value
(time_t)-1.  Since the C and POSIX standards do not require time_t to
be signed, special-case the checks in load_if_changed() and
updateMechList() to treat all mod times as newer than -1.

Signed-off-by: Julien Rische <jrische@redhat.com>
2022-06-15 15:38:15 +02:00
Julien Rische
e9188f0caa 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

Signed-off-by: Julien Rische <jrische@redhat.com>
2022-05-25 11:50:56 +02:00
Julien Rische
c25a51c969 Use p11-kit as default PKCS11 module
Resolves: rhbz#2073274

Signed-off-by: Julien Rische <jrische@redhat.com>
2022-05-02 19:03:37 +02:00
Julien Rische
04513849e3 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-26 13:38:51 +02:00
Alexander Bokovoy
fc958d4773 Fix libkrad client cleanup code
Resolves: rhbz#2072059

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2022-04-05 22:18:53 +03:00
Alexander Bokovoy
29a69aee06 fix dist macro 2022-04-05 16:52:33 +03:00
Alexander Bokovoy
0ceb166d96 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:51:11 +03:00
Julien Rische
2ef37ab30d 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 12:28:27 +01:00
Zbigniew Jędrzejewski-Szmek
970430cbff Drop link flags from krb5-config
Introspecing krb5-config shows that all of the flags in LDFLAGS= are
inappropriate for export, so just drop them all.
2022-02-09 10:54:56 +01:00
Zbigniew Jędrzejewski-Szmek
f858c7e550 Drop old trigger scriptlet
1.15.1 was ~2017, so there is no need to support upgrades from such old
systemd. This allows the dependency on grep to be dropped. grep pulls
in pcre, but most other programs in the core group depend on the newer
pcre2, so it's nicer to avoid pulling in pcre in minimal installations.
2022-02-08 14:07:47 +01:00
Alexander Bokovoy
b998554176 Temporarily remove package note to unblock krb5-dependent packages
Resolves: rhbz#2048909

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
2022-02-03 12:27:25 +02:00
Fedora Release Engineering
75355e197a - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2022-01-20 15:08:32 +00:00
Antonio Torres
ad88d4fd50 Add patches to support OpenSSL 3.0.0
Signed-off-by: Antonio Torres <antorres@redhat.com>
2021-12-03 11:25:46 +01:00
Sahana Prasad
70255ea5b0 Rebuilt with OpenSSL 3.0.0 2021-09-14 19:05:45 +02:00
Robbie Harwood
91c904e5df Remove -specs= from krb5-config output 2021-08-24 17:13:22 +00:00
Robbie Harwood
ca196a9d6b Fix KDC null deref on TGS inner body null server (CVE-2021-37750) 2021-08-19 12:29:56 -04:00
Robbie Harwood
03e8c69837 Add sources 2021-07-26 14:50:12 -04:00
Robbie Harwood
c4016b4e4c New upstream version (1.19.2) 2021-07-26 14:49:39 -04:00
Robbie Harwood
2484569caa Fix defcred leak in krb5 gss_inquire_cred() 2021-07-21 12:44:26 -04:00
Robbie Harwood
6a2eeb9666 Fix KDC null deref on bad encrypted challenge (CVE-2021-36222) 2021-07-12 13:11:12 -04:00
Robbie Harwood
af96dc0c6c Fix use-after-free during krad remote_shutdown() 2021-07-01 13:17:47 -04:00
Robbie Harwood
c5044b0741 MEMORY locking fix and static analysis pullup 2021-06-28 17:50:46 -04:00
Robbie Harwood
91bbbda93f Add the backward-compatible parts of openssl3 support 2021-06-21 13:16:44 -04:00
Robbie Harwood
4df0096f20 Fix three canonicalization cases for fallback 2021-06-09 10:55:13 -04:00
Robbie Harwood
65a1e5607c Fix doc build for Sphinx 4.0 2021-06-02 12:09:09 -04:00
Robbie Harwood
72e80d67ef Add all the sssd-kcm workarounds 2021-05-20 17:26:12 -04:00
Robbie Harwood
c4150c67d1 Fix context for previous backport 2021-05-20 13:59:39 -04:00
Robbie Harwood
904d264a41 Add KCM_OP_GET_CRED_LIST and KCM_OP_RETRIEVE support 2021-05-20 13:48:19 -04:00
Robbie Harwood
69e05d5e39 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.
2021-05-04 15:21:05 -04:00
Robbie Harwood
e9fb111a11 Suppress static analyzer warning in FIPS override 2021-05-04 15:02:53 -04:00
Robbie Harwood
1c2362203e Add rpminspect configuration 2021-05-03 17:50:44 -04:00
Robbie Harwood
c183c8de7d Fix the mess the mass rebuild made of Release 2021-03-30 14:36:09 -04:00
Miroslav Vadkerti
7ef4909316 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:31:53 -04:00
Robbie Harwood
14c7d0b635 Merge #6 Update tests/inplace-upgrade-sanity-test/runtest.sh 2021-03-30 13:07:35 +00:00
Filip Dvorak
002bf4053e Update tests/inplace-upgrade-sanity-test/Makefile
Added setools-console package into Makefile.
2021-03-30 08:29:53 +00:00
Filip Dvorak
d67d35a3c6 Update tests/inplace-upgrade-sanity-test/runtest.sh 2021-03-29 15:21:43 +00:00
Zbigniew Jędrzejewski-Szmek
cf3e70c97c Rebuilt for updated systemd-rpm-macros
See https://pagure.io/fesco/issue/2583.
2021-03-02 16:13:34 +01:00
Robbie Harwood
1c03da79de Further test dependency fixes; no code changes 2021-03-01 16:49:32 -05:00
Robbie Harwood
d20ec5d3bc Make test dependencies contingent on skipcheck; no code changes 2021-03-01 21:27:49 +00:00
Robbie Harwood
ab3f34f0e7 ... including the sources this time 2021-02-18 16:52:28 -05:00
Robbie Harwood
3faaf11da7 New upstream version (1.19.1) 2021-02-18 16:51:47 -05:00
Robbie Harwood
00a0ac8abc Restore krb5_set_default_tgs_ktypes() 2021-02-17 16:12:41 -05:00
Robbie Harwood
d3ac4cf9b0 Hoist the KDC_RUN_DIR check 2021-02-15 15:54:54 -05:00
Robbie Harwood
35a4aa7b99 No code change; just coping with reverted autoconf 2021-02-05 20:39:13 +00:00
Robbie Harwood
90bc2e25b3 Cope with autoconf rollback 2021-02-05 15:33:20 -05:00
Robbie Harwood
d5839d0511 New upstream version (1.19) 2021-02-02 15:32:32 +00:00
Robbie Harwood
105082cb42 Hoist and add an option for disabling %check 2021-02-01 16:21:47 -05:00
Robbie Harwood
0dd40e4ff0 Support host-based GSS initiator names 2021-01-28 13:18:14 -05:00
Robbie Harwood
042ca4af99 Require krb5-pkinit from krb5-{server,workstation} 2021-01-28 16:37:37 +00:00
Robbie Harwood
54bf131a4a Fix up weird mass rebuild versioning 2021-01-28 16:16:22 +00:00
Robbie Harwood
ef09340be0 Add APIs for marshalling credentials 2021-01-28 10:56:02 -05:00
Robbie Harwood
327ebd0b26 Cope with new autotools behavior wrt runstatedir 2021-01-27 14:45:26 -05:00
Fedora Release Engineering
b23f8f6215 - Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng@fedoraproject.org>
2021-01-26 16:06:22 +00:00
Robbie Harwood
9fb5239517 New upstream version (1.19-beta2) 2021-01-12 12:45:35 -05:00
Robbie Harwood
0da55d6175 New upstream version (1.19-beta1) 2020-12-16 16:30:40 -05:00
Robbie Harwood
58924baeb4 Fix runstatedir configuration
Why couldn't systemd just leave it alone?

Partially reverts ec1ab43ca2 .
2020-12-16 11:20:57 -05:00
Robbie Harwood
ed80b08062 Add make to BuildRequires
Drop cmake since we don't use it for anything
2020-12-01 14:37:26 -05:00
Robbie Harwood
b783a5421c Document -k option in kvno(1) synopsis 2020-11-24 12:55:33 -05:00
Robbie Harwood
ab7a2a35c2 Upstream executable shared libraries patch 2020-11-20 11:43:18 -05:00
Robbie Harwood
dc8775d11d Fix build failure in -1 2020-11-18 13:33:37 -05:00
Robbie Harwood
5facc9df4d New upstream version (1.18.3) 2020-11-18 18:16:20 +00:00
Robbie Harwood
015255764a Sigh, date fix 2020-11-17 12:50:36 -05:00
Robbie Harwood
ec1ab43ca2 Migrate /var/run to /run, an exercise in pointlessness
Resolves: #1898410
2020-11-17 12:27:42 -05:00
109 changed files with 25559 additions and 9070 deletions

1
.fmf/version Normal file
View file

@ -0,0 +1 @@
1

113
.gitignore vendored
View file

@ -1,49 +1,50 @@
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
/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.9-beta2.tar.gz
/krb5-1.9-beta2.tar.gz.asc
/krb5-1.9-beta2-pdf.tar.bz2
@ -187,3 +188,23 @@ krb5-1.8.3-pdf.tar.gz
/krb5-1.18.1.tar.gz.asc
/krb5-1.18.2.tar.gz
/krb5-1.18.2.tar.gz.asc
/krb5-1.18.3.tar.gz
/krb5-1.18.3.tar.gz.asc
/krb5-1.19-beta1.tar.gz
/krb5-1.19-beta1.tar.gz.asc
/krb5-1.19-beta2.tar.gz
/krb5-1.19-beta2.tar.gz.asc
/krb5-1.19.tar.gz
/krb5-1.19.tar.gz.asc
/krb5-1.19.1.tar.gz
/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

@ -0,0 +1,310 @@
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,4 +1,4 @@
From 9feb7298b90d3e6a34821fce7315757c0bf81c9e Mon Sep 17 00:00:00 2001
From de4205c45e310ceaaa7cd7958af7293322fa43a6 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 2394f7e33..830203683 100644
index 3d66a876b3..ce3c5a9bac 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -1675,3 +1675,72 @@ if test "$with_ldap" = yes; then
@@ -1458,3 +1458,72 @@ if test "$with_ldap" = yes; then
OPENLDAP_PLUGIN=yes
fi
])dnl
@ -107,7 +107,7 @@ index 2394f7e33..830203683 100644
+])dnl
+
diff --git a/src/clients/ksu/Makefile.in b/src/clients/ksu/Makefile.in
index 8b4edce4d..9d58f29b5 100644
index 8b4edce4d8..9d58f29b5d 100644
--- a/src/clients/ksu/Makefile.in
+++ b/src/clients/ksu/Makefile.in
@@ -3,12 +3,14 @@ BUILDTOP=$(REL)..$(S)..
@ -145,11 +145,11 @@ index 8b4edce4d..9d58f29b5 100644
clean:
$(RM) ksu
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
index 57c349200..508242e0e 100644
index af12861729..931f054041 100644
--- a/src/clients/ksu/main.c
+++ b/src/clients/ksu/main.c
@@ -26,6 +26,7 @@
* KSU was writen by: Ari Medvinsky, ari@isi.edu
* KSU was written by: Ari Medvinsky, ari@isi.edu
*/
+#include "autoconf.h"
@ -303,7 +303,7 @@ index 57c349200..508242e0e 100644
}
diff --git a/src/clients/ksu/pam.c b/src/clients/ksu/pam.c
new file mode 100644
index 000000000..cbfe48704
index 0000000000..cbfe487047
--- /dev/null
+++ b/src/clients/ksu/pam.c
@@ -0,0 +1,389 @@
@ -698,7 +698,7 @@ index 000000000..cbfe48704
+#endif
diff --git a/src/clients/ksu/pam.h b/src/clients/ksu/pam.h
new file mode 100644
index 000000000..0ab76569c
index 0000000000..0ab76569cb
--- /dev/null
+++ b/src/clients/ksu/pam.h
@@ -0,0 +1,57 @@
@ -760,10 +760,10 @@ index 000000000..0ab76569c
+void appl_pam_cleanup(void);
+#endif
diff --git a/src/configure.ac b/src/configure.ac
index 234f4281c..d1f576124 100644
index 77be7a2025..587221936e 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1390,6 +1390,8 @@ AC_SUBST([VERTO_VERSION])
@@ -1399,6 +1399,8 @@ AC_SUBST([VERTO_VERSION])
AC_PATH_PROG(GROFF, groff)
@ -772,3 +772,6 @@ index 234f4281c..d1f576124 100644
# Make localedir work in autoconf 2.5x.
if test "${localedir+set}" != set; then
localedir='$(datadir)/locale'
--
2.45.1

View file

@ -1,4 +1,4 @@
From f8c70f6190a0573e2aca0b40964cf3b1a73ca8bb Mon Sep 17 00:00:00 2001
From 30ff501e4b519396f5aea25e24919be817863e7c 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,7 +36,9 @@ 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.18-beta1
Last-updated: krb5-1.20.1
[jrische@redhat.com: Replace deprecated security_context_t by char *:
- src/util/support/selinux.c]
---
src/aclocal.m4 | 48 +++
src/build-tools/krb5-config.in | 3 +-
@ -61,16 +63,16 @@ Last-updated: krb5-1.18-beta1
.../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 | 406 ++++++++++++++++++
24 files changed, 573 insertions(+), 21 deletions(-)
src/util/support/selinux.c | 405 ++++++++++++++++++
24 files changed, 572 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 830203683..6796fec53 100644
index ce3c5a9bac..3331970930 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -89,6 +89,7 @@ AC_SUBST_FILE(libnodeps_frag)
@@ -85,6 +85,7 @@ AC_SUBST_FILE(libnodeps_frag)
dnl
KRB5_AC_PRAGMA_WEAK_REF
WITH_LDAP
@ -78,7 +80,7 @@ index 830203683..6796fec53 100644
KRB5_LIB_PARAMS
KRB5_AC_INITFINI
KRB5_AC_ENABLE_THREADS
@@ -1743,4 +1744,51 @@ AC_SUBST(PAM_LIBS)
@@ -1526,4 +1527,51 @@ AC_SUBST(PAM_LIBS)
AC_SUBST(PAM_MAN)
AC_SUBST(NON_PAM_MAN)
])dnl
@ -131,10 +133,10 @@ index 830203683..6796fec53 100644
+AC_SUBST(SELINUX_LIBS)
+])dnl
diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in
index f6184da3f..c17cb5eb5 100755
index 8e6eb86601..7677f37359 100755
--- a/src/build-tools/krb5-config.in
+++ b/src/build-tools/krb5-config.in
@@ -41,6 +41,7 @@ DL_LIB='@DL_LIB@'
@@ -40,6 +40,7 @@ DL_LIB='@DL_LIB@'
DEFCCNAME='@DEFCCNAME@'
DEFKTNAME='@DEFKTNAME@'
DEFCKTNAME='@DEFCKTNAME@'
@ -142,7 +144,7 @@ index f6184da3f..c17cb5eb5 100755
LIBS='@LIBS@'
GEN_LIB=@GEN_LIB@
@@ -255,7 +256,7 @@ if test -n "$do_libs"; then
@@ -253,7 +254,7 @@ if test -n "$do_libs"; then
fi
# If we ever support a flag to generate output suitable for static
@ -152,7 +154,7 @@ index f6184da3f..c17cb5eb5 100755
echo $lib_flags
diff --git a/src/config/pre.in b/src/config/pre.in
index ce87e21ca..917357df9 100644
index a0c60c70b3..7eaa2f351c 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -177,6 +177,7 @@ LD = $(PURE) @LD@
@ -163,7 +165,7 @@ index ce87e21ca..917357df9 100644
INSTALL=@INSTALL@
INSTALL_STRIP=
@@ -402,7 +403,7 @@ SUPPORT_LIB = -l$(SUPPORT_LIBNAME)
@@ -379,7 +380,7 @@ SUPPORT_LIB = -l$(SUPPORT_LIBNAME)
# HESIOD_LIBS is -lhesiod...
HESIOD_LIBS = @HESIOD_LIBS@
@ -173,10 +175,10 @@ index ce87e21ca..917357df9 100644
GSS_LIBS = $(GSS_KRB5_LIB)
# needs fixing if ever used on macOS!
diff --git a/src/configure.ac b/src/configure.ac
index d1f576124..440a22bd9 100644
index 587221936e..69be9030f8 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1392,6 +1392,8 @@ AC_PATH_PROG(GROFF, groff)
@@ -1401,6 +1401,8 @@ AC_PATH_PROG(GROFF, groff)
KRB5_WITH_PAM
@ -186,7 +188,7 @@ index d1f576124..440a22bd9 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 9616b24bf..0d9af3d95 100644
index 1d1c8293f4..768110e5ef 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -128,6 +128,7 @@ typedef unsigned char u_char;
@ -199,7 +201,7 @@ index 9616b24bf..0d9af3d95 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 000000000..dfaaa847c
index 0000000000..dfaaa847cb
--- /dev/null
+++ b/src/include/k5-label.h
@@ -0,0 +1,32 @@
@ -236,10 +238,10 @@ index 000000000..dfaaa847c
+#endif
+#endif
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 79761f6d2..e9435c693 100644
index 4e09ed345d..09f800be52 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -87,6 +87,12 @@
@@ -83,6 +83,12 @@
#define THREEPARAMOPEN(x,y,z) open(x,y,z)
#endif
@ -253,7 +255,7 @@ index 79761f6d2..e9435c693 100644
#include <stdlib.h>
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
index 301e3476d..19f2cc230 100644
index a89b5144f6..4d6cc0bdf9 100644
--- a/src/kadmin/dbutil/dump.c
+++ b/src/kadmin/dbutil/dump.c
@@ -148,12 +148,21 @@ create_ofile(char *ofile, char **tmpname)
@ -288,10 +290,10 @@ index 301e3476d..19f2cc230 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 fdcd694d7..1ede4bf2f 100644
index bfdfef5c48..b43fe9a082 100644
--- a/src/kdc/main.c
+++ b/src/kdc/main.c
@@ -872,7 +872,7 @@ write_pid_file(const char *path)
@@ -844,7 +844,7 @@ write_pid_file(const char *path)
FILE *file;
unsigned long pid;
@ -301,10 +303,10 @@ index fdcd694d7..1ede4bf2f 100644
return errno;
pid = (unsigned long) getpid();
diff --git a/src/kprop/kpropd.c b/src/kprop/kpropd.c
index 5622d56e1..356e3e0e6 100644
index aa3c81ea30..cb9785aaeb 100644
--- a/src/kprop/kpropd.c
+++ b/src/kprop/kpropd.c
@@ -487,6 +487,9 @@ doit(int fd)
@@ -488,6 +488,9 @@ doit(int fd)
krb5_enctype etype;
int database_fd;
char host[INET6_ADDRSTRLEN + 1];
@ -314,7 +316,7 @@ index 5622d56e1..356e3e0e6 100644
signal_wrapper(SIGALRM, alarm_handler);
alarm(params.iprop_resync_timeout);
@@ -542,9 +545,15 @@ doit(int fd)
@@ -543,9 +546,15 @@ doit(int fd)
free(name);
exit(1);
}
@ -331,10 +333,10 @@ index 5622d56e1..356e3e0e6 100644
KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK);
if (retval) {
diff --git a/src/lib/kadm5/logger.c b/src/lib/kadm5/logger.c
index c6885edf2..9aec3c05e 100644
index e14da53790..b879a4049b 100644
--- a/src/lib/kadm5/logger.c
+++ b/src/lib/kadm5/logger.c
@@ -309,7 +309,7 @@ krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do
@@ -310,7 +310,7 @@ krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do
*/
append = (cp[4] == ':') ? O_APPEND : 0;
if (append || cp[4] == '=') {
@ -343,7 +345,7 @@ index c6885edf2..9aec3c05e 100644
S_IRUSR | S_IWUSR | S_IRGRP);
if (fd != -1)
f = fdopen(fd, append ? "a" : "w");
@@ -776,7 +776,7 @@ krb5_klog_reopen(krb5_context kcontext)
@@ -777,7 +777,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.
*/
@ -353,7 +355,7 @@ index c6885edf2..9aec3c05e 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 2659a2501..e9b95fce5 100644
index 2659a25018..e9b95fce59 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)
@ -366,7 +368,7 @@ index 2659a2501..e9b95fce5 100644
retval = errno;
goto cleanup;
diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c
index 7b100a0ec..5683a0433 100644
index 1da40b51d0..f3ab7340a6 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)
@ -416,7 +418,7 @@ index 7b100a0ec..5683a0433 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 021c94398..aaf573439 100644
index e510211fc5..f3ea28c8ec 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)
@ -437,10 +439,10 @@ index 021c94398..aaf573439 100644
goto report_errno;
writevno = 1;
diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
index 7073459f0..e9b99f4ca 100644
index 4cbbbb270a..c4058ddc96 100644
--- a/src/lib/krb5/os/trace.c
+++ b/src/lib/krb5/os/trace.c
@@ -458,7 +458,7 @@ krb5_set_trace_filename(krb5_context context, const char *filename)
@@ -460,7 +460,7 @@ krb5_set_trace_filename(krb5_context context, const char *filename)
fd = malloc(sizeof(*fd));
if (fd == NULL)
return ENOMEM;
@ -450,7 +452,7 @@ index 7073459f0..e9b99f4ca 100644
free(fd);
return errno;
diff --git a/src/plugins/kdb/db2/adb_openclose.c b/src/plugins/kdb/db2/adb_openclose.c
index 7db30a33b..2b9d01921 100644
index 9a506e9d44..f92ab47143 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,
@ -463,7 +465,7 @@ index 7db30a33b..2b9d01921 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 5106a5c99..e481e8121 100644
index 2c163d91cc..9a344a603e 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)
@ -478,7 +480,7 @@ index 5106a5c99..e481e8121 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 2977b17f3..d5809a5a9 100644
index 2977b17f3a..d5809a5a93 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";
@ -499,7 +501,7 @@ index 2977b17f3..d5809a5a9 100644
} else {
diff --git a/src/plugins/kdb/db2/libdb2/hash/hash.c b/src/plugins/kdb/db2/libdb2/hash/hash.c
index 862dbb164..686a960c9 100644
index 862dbb1640..686a960c96 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";
@ -520,7 +522,7 @@ index 862dbb164..686a960c9 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 d8b26e701..b0daa7c02 100644
index d8b26e7011..b0daa7c021 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";
@ -542,7 +544,7 @@ index d8b26e701..b0daa7c02 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 b92cb58c7..0a95101ad 100644
index e87688d666..30f7c00ab5 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)
@ -579,7 +581,7 @@ index b92cb58c7..0a95101ad 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 aa951df05..79f9500f6 100644
index aa951df05f..79f9500f69 100644
--- a/src/util/profile/prof_file.c
+++ b/src/util/profile/prof_file.c
@@ -33,6 +33,7 @@
@ -600,7 +602,7 @@ index aa951df05..79f9500f6 100644
retval = errno;
if (retval == 0)
diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in
index 86d5a950a..1052d53a1 100644
index 86d5a950a6..1052d53a1e 100644
--- a/src/util/support/Makefile.in
+++ b/src/util/support/Makefile.in
@@ -74,6 +74,7 @@ IPC_SYMS= \
@ -622,10 +624,10 @@ index 86d5a950a..1052d53a1 100644
diff --git a/src/util/support/selinux.c b/src/util/support/selinux.c
new file mode 100644
index 000000000..6d41f3244
index 0000000000..807d039da3
--- /dev/null
+++ b/src/util/support/selinux.c
@@ -0,0 +1,406 @@
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2007,2008,2009,2011,2012,2013,2016 Red Hat, Inc. All Rights Reserved.
+ *
@ -724,17 +726,16 @@ index 000000000..6d41f3244
+ }
+}
+
+static security_context_t
+static char *
+push_fscreatecon(const char *pathname, mode_t mode)
+{
+ security_context_t previous, configuredsc, currentsc, derivedsc;
+ char *previous, *configuredsc, *currentsc, *genpath;
+ const char *derivedsc, *fullpath, *currentuser;
+ context_t current, derived;
+ const char *fullpath, *currentuser;
+ char *genpath;
+
+ previous = configuredsc = currentsc = derivedsc = NULL;
+ previous = configuredsc = currentsc = genpath = NULL;
+ derivedsc = NULL;
+ current = derived = NULL;
+ genpath = NULL;
+
+ fullpath = pathname;
+
@ -862,7 +863,7 @@ index 000000000..6d41f3244
+}
+
+static void
+pop_fscreatecon(security_context_t previous)
+pop_fscreatecon(char *previous)
+{
+ if (!is_selinux_enabled()) {
+ return;
@ -916,7 +917,7 @@ index 000000000..6d41f3244
+{
+ FILE *fp;
+ int errno_save;
+ security_context_t ctx;
+ char *ctx;
+
+ if ((strcmp(mode, "r") == 0) ||
+ (strcmp(mode, "rb") == 0)) {
@ -942,7 +943,7 @@ index 000000000..6d41f3244
+{
+ int fd;
+ int errno_save;
+ security_context_t ctx;
+ char *ctx;
+
+ k5_once(&labeled_once, label_mutex_init);
+ k5_mutex_lock(&labeled_mutex);
@ -963,7 +964,7 @@ index 000000000..6d41f3244
+{
+ int ret;
+ int errno_save;
+ security_context_t ctx;
+ char *ctx;
+
+ k5_once(&labeled_once, label_mutex_init);
+ k5_mutex_lock(&labeled_mutex);
@ -984,7 +985,7 @@ index 000000000..6d41f3244
+{
+ int ret;
+ int errno_save;
+ security_context_t ctx;
+ char *ctx;
+
+ k5_once(&labeled_once, label_mutex_init);
+ k5_mutex_lock(&labeled_mutex);
@ -1005,7 +1006,7 @@ index 000000000..6d41f3244
+{
+ int fd;
+ int errno_save;
+ security_context_t ctx;
+ char *ctx;
+ mode_t mode;
+ va_list ap;
+
@ -1032,3 +1033,6 @@ index 000000000..6d41f3244
+}
+
+#endif /* USE_SELINUX */
--
2.45.1

View file

@ -1,4 +1,4 @@
From c6e103db0eb02c31a13b8cbcbae296c473074991 Mon Sep 17 00:00:00 2001
From 393830d96000ed692aa9a99ef87187d6f2863931 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 adfea6e2b..d1327e400 100644
index adfea6e2b5..d1327e400b 100644
--- a/src/kadmin/cli/Makefile.in
+++ b/src/kadmin/cli/Makefile.in
@@ -37,3 +37,8 @@ clean-unix::
@ -27,7 +27,7 @@ index adfea6e2b..d1327e400 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 8669c2436..a22f23c02 100644
index 8669c2436c..a22f23c02c 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,3 +39,6 @@ index 8669c2436..a22f23c02 100644
install:
$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
--
2.45.1

View file

@ -1,4 +1,4 @@
From bf8521bfaa4a4d54f6eb94f785c68942f4afa055 Mon Sep 17 00:00:00 2001
From 7b6453903c248a761d3ceb538dfacebbf3d3a9ff 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
@ -19,10 +19,12 @@ post6 restores MD4 (and therefore keygen-only RC4).
post7 restores MD5 and adds radius_md5_fips_override.
Last-updated: krb5-1.17
post8 silences a static analyzer warning.
Last-updated: krb5-1.20
---
doc/admin/conf_files/krb5_conf.rst | 6 +++
src/lib/crypto/krb/prng.c | 11 ++++-
src/lib/crypto/krb/prng.c | 15 +++++-
.../crypto/openssl/enc_provider/camellia.c | 6 +++
src/lib/crypto/openssl/enc_provider/rc4.c | 13 +++++-
.../crypto/openssl/hash_provider/hash_evp.c | 12 +++++
@ -36,13 +38,13 @@ Last-updated: krb5-1.17
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, 151 insertions(+), 33 deletions(-)
15 files changed, 155 insertions(+), 33 deletions(-)
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 1d2aa7f68..3a8b9cf47 100644
index f22d5db11b..a33711d918 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -331,6 +331,12 @@ The libdefaults section may contain any of the following relations:
@@ -330,6 +330,12 @@ The libdefaults section may contain any of the following relations:
qualification of shortnames, set this relation to the empty string
with ``qualify_shortname = ""``. (New in release 1.18.)
@ -56,22 +58,26 @@ index 1d2aa7f68..3a8b9cf47 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 cb9ca9b98..f0e9984ca 100644
index d6b79e2dea..9e80a03d21 100644
--- a/src/lib/crypto/krb/prng.c
+++ b/src/lib/crypto/krb/prng.c
@@ -26,6 +26,8 @@
@@ -26,6 +26,12 @@
#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)
{
@@ -99,9 +101,16 @@ krb5_boolean
k5_get_os_entropy(unsigned char *buf, size_t len, int strong)
@@ -96,9 +102,16 @@ cleanup:
static krb5_boolean
get_os_entropy(unsigned char *buf, size_t len)
{
const char *device;
-#if defined(__linux__) && defined(SYS_getrandom)
int r;
@ -87,10 +93,10 @@ index cb9ca9b98..f0e9984ca 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 2da691329..f79679a0b 100644
index 01920e6ce1..d9f327add6 100644
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
@@ -304,6 +304,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
@@ -387,6 +387,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;
@ -100,7 +106,7 @@ index 2da691329..f79679a0b 100644
if (output->length < CAMELLIA_BLOCK_SIZE)
return KRB5_BAD_MSIZE;
@@ -331,6 +334,9 @@ static krb5_error_code
@@ -418,6 +421,9 @@ static krb5_error_code
krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
krb5_data *state)
{
@ -111,10 +117,10 @@ index 2da691329..f79679a0b 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 a65d57b7a..6ccaca94a 100644
index 448d563348..ce63cb5f1b 100644
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
@@ -66,6 +66,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
@@ -69,6 +69,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
EVP_CIPHER_CTX *ctx = NULL;
struct arcfour_state *arcstate;
@ -124,7 +130,7 @@ index a65d57b7a..6ccaca94a 100644
arcstate = (state != NULL) ? (void *)state->data : NULL;
if (arcstate != NULL) {
ctx = arcstate->ctx;
@@ -113,7 +116,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
@@ -116,7 +119,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
static void
k5_arcfour_free_state(krb5_data *state)
{
@ -138,7 +144,7 @@ index a65d57b7a..6ccaca94a 100644
EVP_CIPHER_CTX_free(arcstate->ctx);
free(arcstate);
@@ -125,6 +133,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
@@ -128,6 +136,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
{
struct arcfour_state *arcstate;
@ -149,10 +155,10 @@ index a65d57b7a..6ccaca94a 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 1e0fb8fc3..2eb5139c0 100644
index f2fbffdb29..11659908bb 100644
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
@@ -49,6 +49,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
@@ -60,6 +60,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
if (ctx == NULL)
return ENOMEM;
@ -164,7 +170,7 @@ index 1e0fb8fc3..2eb5139c0 100644
ok = EVP_DigestInit_ex(ctx, type, NULL);
for (i = 0; i < num_data; i++) {
if (!SIGN_IOV(&data[i]))
@@ -64,12 +69,19 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
@@ -78,6 +83,11 @@ 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)
{
@ -176,6 +182,7 @@ index 1e0fb8fc3..2eb5139c0 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)
{
@ -185,24 +192,24 @@ index 1e0fb8fc3..2eb5139c0 100644
}
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
index 7dc59dcc0..769a50c00 100644
index bf12b8d6a0..f21e268f7f 100644
--- a/src/lib/crypto/openssl/hmac.c
+++ b/src/lib/crypto/openssl/hmac.c
@@ -103,7 +103,11 @@ map_digest(const struct krb5_hash_provider *hash)
@@ -111,7 +111,11 @@ map_digest(const struct krb5_hash_provider *hash)
return EVP_sha256();
else if (!strncmp(hash->hash_name, "SHA-384",7))
else if (hash == &krb5int_hash_sha384)
return EVP_sha384();
- else if (!strncmp(hash->hash_name, "MD5", 3))
- else if (hash == &krb5int_hash_md5)
+
+ if (FIPS_mode())
+ return NULL;
+
+ if (!strncmp(hash->hash_name, "MD5", 3))
+ if (hash == &krb5int_hash_md5)
return EVP_md5();
else if (!strncmp(hash->hash_name, "MD4", 3))
else if (hash == &krb5int_hash_md4)
return EVP_md4();
diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
index 9c13d9d75..42d354a3b 100644
index 9c13d9d755..42d354a3b5 100644
--- a/src/lib/krad/attr.c
+++ b/src/lib/krad/attr.c
@@ -38,7 +38,8 @@
@ -326,7 +333,7 @@ index 9c13d9d75..42d354a3b 100644
krad_attr
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
index 03c613716..d89982a13 100644
index f309f1581c..6ec031e320 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)
@ -349,7 +356,7 @@ index 03c613716..d89982a13 100644
return retval;
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
index 996a89372..312dc8258 100644
index 7619563fc5..e123763954 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -39,6 +39,8 @@
@ -395,7 +402,7 @@ index 996a89372..312dc8258 100644
/* Decode attributes from a buffer. */
krb5_error_code
@@ -152,4 +163,17 @@ gai_error_code(int err)
@@ -156,4 +167,17 @@ gai_error_code(int err)
}
}
@ -407,14 +414,14 @@ index 996a89372..312dc8258 100644
+ if (!FIPS_mode())
+ return 0;
+
+ profile_get_boolean(ctx->profile, "libdefaults",
+ "radius_md5_fips_override", NULL, 0, &val);
+ (void)profile_get_boolean(ctx->profile, "libdefaults",
+ "radius_md5_fips_override", NULL, 0, &val);
+ return !val;
+}
+
#endif /* INTERNAL_H_ */
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
index c597174b6..fc2d24800 100644
index c597174b65..fc2d248001 100644
--- a/src/lib/krad/packet.c
+++ b/src/lib/krad/packet.c
@@ -53,12 +53,6 @@ typedef unsigned char uchar;
@ -475,7 +482,7 @@ index c597174b6..fc2d24800 100644
}
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
index 437f7e91a..0f90443ce 100644
index 06ae751bc8..929f1cef67 100644
--- a/src/lib/krad/remote.c
+++ b/src/lib/krad/remote.c
@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr)
@ -496,7 +503,7 @@ index 437f7e91a..0f90443ce 100644
request_finish(r, 0, rsp);
break;
}
@@ -455,6 +455,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
@@ -460,6 +460,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;
@ -510,7 +517,7 @@ index 437f7e91a..0f90443ce 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 eb2a780c8..4d285ad9d 100644
index eb2a780c89..4d285ad9de 100644
--- a/src/lib/krad/t_attr.c
+++ b/src/lib/krad/t_attr.c
@@ -50,6 +50,7 @@ main()
@ -531,7 +538,7 @@ index eb2a780c8..4d285ad9d 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 7928335ca..0f9576253 100644
index 7928335ca4..0f95762534 100644
--- a/src/lib/krad/t_attrset.c
+++ b/src/lib/krad/t_attrset.c
@@ -49,6 +49,7 @@ main()
@ -553,7 +560,7 @@ index 7928335ca..0f9576253 100644
/* Manually encode User-Name. */
diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
index 00734a13b..a3ce22b70 100644
index 00734a13b5..a3ce22b70f 100644
--- a/src/plugins/preauth/spake/spake_client.c
+++ b/src/plugins/preauth/spake/spake_client.c
@@ -38,6 +38,8 @@
@ -577,7 +584,7 @@ index 00734a13b..a3ce22b70 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 88c964ce1..c7df0392f 100644
index 1a772d450f..232e78bc05 100644
--- a/src/plugins/preauth/spake/spake_kdc.c
+++ b/src/plugins/preauth/spake/spake_kdc.c
@@ -41,6 +41,8 @@
@ -589,7 +596,7 @@ index 88c964ce1..c7df0392f 100644
/*
* The SPAKE kdcpreauth module uses a secure cookie containing the following
* concatenated fields (all integer fields are big-endian):
@@ -571,6 +573,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
@@ -551,6 +553,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
if (maj_ver != 1)
return KRB5_PLUGIN_VER_NOTSUPP;
@ -600,3 +607,6 @@ index 88c964ce1..c7df0392f 100644
vt = (krb5_kdcpreauth_vtable)vtable;
vt->name = "spake";
vt->pa_type_list = pa_types;
--
2.45.1

View file

@ -0,0 +1,82 @@
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

@ -0,0 +1,41 @@
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

@ -0,0 +1,120 @@
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

@ -0,0 +1,31 @@
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

@ -0,0 +1,165 @@
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

@ -0,0 +1,280 @@
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

@ -0,0 +1,47 @@
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

@ -0,0 +1,218 @@
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

@ -0,0 +1,64 @@
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

@ -0,0 +1,206 @@
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

@ -0,0 +1,71 @@
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

@ -0,0 +1,34 @@
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

@ -0,0 +1,226 @@
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

@ -0,0 +1,138 @@
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

@ -0,0 +1,265 @@
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

@ -0,0 +1,629 @@
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

@ -0,0 +1,78 @@
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

@ -0,0 +1,264 @@
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

@ -0,0 +1,157 @@
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

@ -0,0 +1,202 @@
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

@ -0,0 +1,599 @@
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

@ -0,0 +1,61 @@
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

@ -0,0 +1,64 @@
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

@ -0,0 +1,327 @@
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

@ -0,0 +1,260 @@
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

@ -0,0 +1,692 @@
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

@ -0,0 +1,381 @@
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

@ -0,0 +1,189 @@
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

226
0040-automated-fast.patch Normal file
View file

@ -0,0 +1,226 @@
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

@ -0,0 +1,40 @@
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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,80 +0,0 @@
From 758f5031fe9d6c1e3eb33818bc6d57cf8b4a3a72 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Tue, 22 Sep 2020 01:11:39 +0300
Subject: [PATCH] Adjust KDC alias helper function contract
Change the name of is_client_alias() to is_client_db_alias(), and
change the contract so that the already-canonical principal name comes
from a DB entry (which is less flexible, but clearer since DB entries
always contain canonical principal names). Make the function
available outside of kdc_util.c.
[ghudson@mit.edu: clarified commit message]
(cherry picked from commit 9fb5f572dd6ce808b234cb60a573eac48136d7ca)
---
src/kdc/kdc_util.c | 14 +++++++-------
src/kdc/kdc_util.h | 4 ++++
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index dcb2df8dc..6330387d0 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -1463,10 +1463,10 @@ cleanup:
return code;
}
-/* Return true if princ canonicalizes to the same principal as canon. */
-static krb5_boolean
-is_client_alias(krb5_context context, krb5_const_principal canon,
- krb5_const_principal princ)
+/* Return true if princ canonicalizes to the same principal as entry's. */
+krb5_boolean
+is_client_db_alias(krb5_context context, const krb5_db_entry *entry,
+ krb5_const_principal princ)
{
krb5_error_code ret;
krb5_db_entry *self;
@@ -1475,7 +1475,7 @@ is_client_alias(krb5_context context, krb5_const_principal canon,
ret = krb5_db_get_principal(context, princ,
KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY, &self);
if (!ret) {
- is_self = krb5_principal_compare(context, canon, self->princ);
+ is_self = krb5_principal_compare(context, entry->princ, self->princ);
krb5_db_free_principal(context, self);
}
@@ -1535,7 +1535,7 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
/* If the server is local, check that the request is for self. */
if (!isflagset(c_flags, KRB5_KDB_FLAG_ISSUING_REFERRAL) &&
- !is_client_alias(kdc_context, server->princ, client_princ)) {
+ !is_client_db_alias(kdc_context, server, client_princ)) {
*status = "INVALID_S4U2SELF_REQUEST_SERVER_MISMATCH";
return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; /* match Windows error */
}
@@ -1728,7 +1728,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, unsigned int flags,
}
client_princ = *stkt_authdata_client;
- } else if (!is_client_alias(kdc_context, server->princ, server_princ)) {
+ } else if (!is_client_db_alias(kdc_context, server, server_princ)) {
*status = "EVIDENCE_TICKET_MISMATCH";
return KRB5KDC_ERR_SERVER_NOMATCH;
}
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index 384b21ad2..2c9d8cf69 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -344,6 +344,10 @@ log_tgs_badtrans(krb5_context ctx, krb5_principal cprinc,
void
log_tgs_alt_tgt(krb5_context context, krb5_principal p);
+krb5_boolean
+is_client_db_alias(krb5_context context, const krb5_db_entry *entry,
+ krb5_const_principal princ);
+
/* FAST*/
enum krb5_fast_kdc_flags {
KRB5_FAST_REPLY_KEY_USED = 0x1,

View file

@ -1,65 +0,0 @@
From ccc5b9663e229f20421c01836aa5ecb06f1f2a48 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Tue, 22 Sep 2020 01:17:11 +0300
Subject: [PATCH] Allow aliases when matching U2U second ticket
In process_tgs_req() when verifying the user-to-user second ticket,
compare the canonical names of the request server and the second
ticket client.
[ghudson@mit.edu: expanded commit message; trimmed tests]
ticket: 8951 (new)
(cherry picked from commit afc494ef9418e6be7fbb887364efa6606b10034a)
---
src/kdc/do_tgs_req.c | 2 +-
src/tests/t_u2u.py | 25 +++++++++++++++++++++++++
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 463a9c0dd..74cd19e96 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -666,7 +666,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
*/
krb5_enc_tkt_part *t2enc = request->second_ticket[st_idx]->enc_part2;
krb5_principal client2 = t2enc->client;
- if (!krb5_principal_compare(kdc_context, request->server, client2)) {
+ if (!is_client_db_alias(kdc_context, server, client2)) {
altcprinc = client2;
errcode = KRB5KDC_ERR_SERVER_NOMATCH;
status = "2ND_TKT_MISMATCH";
diff --git a/src/tests/t_u2u.py b/src/tests/t_u2u.py
index 1ca6ac87e..4b8a82a2f 100644
--- a/src/tests/t_u2u.py
+++ b/src/tests/t_u2u.py
@@ -32,4 +32,29 @@ realm.run([kvno, '--u2u', realm.ccache, realm.user_princ])
realm.run([klist])
+realm.stop()
+
+# Load the test KDB module to test aliases
+testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'},
+ 'user': {'keys': 'aes128-cts', 'flags': '+preauth'},
+ 'WIN10': {'keys': 'aes128-cts'}}
+kdcconf = {'realms': {'$realm': {'database_module': 'test'}},
+ 'dbmodules': {'test': {'db_library': 'test',
+ 'princs': testprincs,
+ 'alias': {'HOST/win10': 'WIN10'}}}}
+
+realm = K5Realm(kdc_conf=kdcconf, create_kdb=False)
+realm.start_kdc()
+
+# Create a second user principal and get tickets for it.
+u2u_ccache = 'FILE:' + os.path.join(realm.testdir, 'ccu2u')
+realm.extract_keytab('WIN10', realm.keytab)
+realm.kinit('WIN10', None, ['-k', '-c', u2u_ccache])
+
+realm.extract_keytab(realm.user_princ, realm.keytab)
+realm.kinit(realm.user_princ, None, ['-k'])
+
+realm.run([kvno, '--u2u', u2u_ccache, 'HOST/win10'], expected_msg='kvno = 0')
+realm.run([kvno, '--u2u', u2u_ccache, 'WIN10'], expected_msg='kvno = 0')
+
success('user-to-user tests')

View file

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

View file

@ -1,49 +0,0 @@
From 594c9d225f470e73a46dd2a85c5e50571e90598c Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sat, 11 Jul 2020 21:57:30 -0400
Subject: [PATCH] Allow gss_unwrap_iov() of unpadded RC4 tokens
Windows Remote Management, when used with an RC4 session key, appears
to generate GSS wrap tokens with no padding instead of the expected
one byte (RFC 4757 section 7.3). These tokens cannot be decoded with
gss_unwrap() or a STREAM buffer (even with Microsoft SSPI), but SSPI
allows them to be decoded using explicit IOVs with either a
zero-length padding buffer or no padding buffer. Allow these cases to
work in kg_fixup_padding_iov(). (It is already possible to make this
work with HEADER | DATA | DATA, but only by
accident--kg_fixup_padding_iov() doesn't find a data buffer because
kg_locate_iov() only looks for singleton buffers, so it exits early.)
ticket: 8926 (new)
tags: pullup
target_version: 1.18-next
(cherry picked from commit 3f204ddd567715ef360b4bb0b32961b6a9877f9d)
---
src/lib/gssapi/krb5/util_crypt.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c
index f7d3e92c4..d6c71aeb8 100644
--- a/src/lib/gssapi/krb5/util_crypt.c
+++ b/src/lib/gssapi/krb5/util_crypt.c
@@ -638,16 +638,13 @@ kg_fixup_padding_iov(OM_uint32 *minor_status, gss_iov_buffer_desc *iov,
data = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_DATA);
padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
- if (data == NULL) {
+ /* Do nothing if padding is absent or empty, to allow unwrapping of WinRM
+ * unpadded RC4 tokens using an explicit IOV array. */
+ if (data == NULL || padding == NULL || padding->buffer.length == 0) {
*minor_status = 0;
return GSS_S_COMPLETE;
}
- if (padding == NULL || padding->buffer.length == 0) {
- *minor_status = EINVAL;
- return GSS_S_FAILURE;
- }
-
p = (unsigned char *)padding->buffer.value;
padlength = p[padding->buffer.length - 1];

View file

@ -1,298 +0,0 @@
From dd8b146093d4bdf8a7d0c0eb8156b62d090448d7 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 30 Sep 2020 02:12:00 -0400
Subject: [PATCH] Avoid passing DB entry structures in KDC
When validating AS or TGS requests, pass pointers to DB entry
structures, not the structures themselves.
(cherry picked from commit 7ccc08a889b40693b2ce7f108f2cdda51bc04bff)
---
src/kdc/do_as_req.c | 4 ++--
src/kdc/do_tgs_req.c | 2 +-
src/kdc/kdc_util.c | 34 +++++++++++++++++-----------------
src/kdc/kdc_util.h | 6 +++---
src/kdc/tgs_policy.c | 35 ++++++++++++++++++-----------------
5 files changed, 41 insertions(+), 40 deletions(-)
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index 9ae7b0a5e..c2dfea9b8 100644
--- a/src/kdc/do_as_req.c
+++ b/src/kdc/do_as_req.c
@@ -663,8 +663,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
au_state->stage = VALIDATE_POL;
if ((errcode = validate_as_request(kdc_active_realm,
- state->request, *state->client,
- *state->server, state->kdc_time,
+ state->request, state->client,
+ state->server, state->kdc_time,
&state->status, &state->e_data))) {
errcode += ERROR_TABLE_BASE_krb5;
goto errout;
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 74cd19e96..d345797c4 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -260,7 +260,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
goto cleanup;
if ((retval = validate_tgs_request(kdc_active_realm,
- request, *server, header_ticket,
+ request, server, header_ticket,
kdc_time, &status, &e_data))) {
if (retval == KDC_ERR_POLICY || retval == KDC_ERR_BADOPTION)
au_state->violation = PROT_CONSTRAINT;
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index a4a05b9fa..b2042862a 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -612,8 +612,8 @@ check_anon(kdc_realm_t *kdc_active_realm,
KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_CNAME_IN_ADDL_TKT)
int
validate_as_request(kdc_realm_t *kdc_active_realm,
- krb5_kdc_req *request, krb5_db_entry client,
- krb5_db_entry server, krb5_timestamp kdc_time,
+ krb5_kdc_req *request, krb5_db_entry *client,
+ krb5_db_entry *server, krb5_timestamp kdc_time,
const char **status, krb5_pa_data ***e_data)
{
krb5_error_code ret;
@@ -627,7 +627,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
}
/* The client must not be expired */
- if (client.expiration && ts_after(kdc_time, client.expiration)) {
+ if (client->expiration && ts_after(kdc_time, client->expiration)) {
*status = "CLIENT EXPIRED";
if (vague_errors)
return(KRB_ERR_GENERIC);
@@ -637,8 +637,8 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
/* The client's password must not be expired, unless the server is
a KRB5_KDC_PWCHANGE_SERVICE. */
- if (client.pw_expiration && ts_after(kdc_time, client.pw_expiration) &&
- !isflagset(server.attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
+ if (client->pw_expiration && ts_after(kdc_time, client->pw_expiration) &&
+ !isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
*status = "CLIENT KEY EXPIRED";
if (vague_errors)
return(KRB_ERR_GENERIC);
@@ -647,7 +647,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
}
/* The server must not be expired */
- if (server.expiration && ts_after(kdc_time, server.expiration)) {
+ if (server->expiration && ts_after(kdc_time, server->expiration)) {
*status = "SERVICE EXPIRED";
return(KDC_ERR_SERVICE_EXP);
}
@@ -656,8 +656,8 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
* If the client requires password changing, then only allow the
* pwchange service.
*/
- if (isflagset(client.attributes, KRB5_KDB_REQUIRES_PWCHANGE) &&
- !isflagset(server.attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
+ if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PWCHANGE) &&
+ !isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
*status = "REQUIRED PWCHANGE";
return(KDC_ERR_KEY_EXP);
}
@@ -665,37 +665,37 @@ validate_as_request(kdc_realm_t *kdc_active_realm,
/* Client and server must allow postdating tickets */
if ((isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE) ||
isflagset(request->kdc_options, KDC_OPT_POSTDATED)) &&
- (isflagset(client.attributes, KRB5_KDB_DISALLOW_POSTDATED) ||
- isflagset(server.attributes, KRB5_KDB_DISALLOW_POSTDATED))) {
+ (isflagset(client->attributes, KRB5_KDB_DISALLOW_POSTDATED) ||
+ isflagset(server->attributes, KRB5_KDB_DISALLOW_POSTDATED))) {
*status = "POSTDATE NOT ALLOWED";
return(KDC_ERR_CANNOT_POSTDATE);
}
/* Check to see if client is locked out */
- if (isflagset(client.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
+ if (isflagset(client->attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
*status = "CLIENT LOCKED OUT";
return(KDC_ERR_CLIENT_REVOKED);
}
/* Check to see if server is locked out */
- if (isflagset(server.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
+ if (isflagset(server->attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
*status = "SERVICE LOCKED OUT";
return(KDC_ERR_S_PRINCIPAL_UNKNOWN);
}
/* Check to see if server is allowed to be a service */
- if (isflagset(server.attributes, KRB5_KDB_DISALLOW_SVR)) {
+ if (isflagset(server->attributes, KRB5_KDB_DISALLOW_SVR)) {
*status = "SERVICE NOT ALLOWED";
return(KDC_ERR_MUST_USE_USER2USER);
}
- if (check_anon(kdc_active_realm, client.princ, request->server) != 0) {
+ if (check_anon(kdc_active_realm, client->princ, request->server) != 0) {
*status = "ANONYMOUS NOT ALLOWED";
return(KDC_ERR_POLICY);
}
/* Perform KDB module policy checks. */
- ret = krb5_db_check_policy_as(kdc_context, request, &client, &server,
+ ret = krb5_db_check_policy_as(kdc_context, request, client, server,
kdc_time, status, e_data);
if (ret && ret != KRB5_PLUGIN_OP_NOTSUPP)
return errcode_to_protocol(ret);
@@ -1568,8 +1568,8 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
princ->pw_expiration = 0;
clear(princ->attributes, KRB5_KDB_REQUIRES_PWCHANGE);
- code = validate_as_request(kdc_active_realm, request, *princ,
- no_server, kdc_time, status, &e_data);
+ code = validate_as_request(kdc_active_realm, request, princ,
+ &no_server, kdc_time, status, &e_data);
if (code) {
krb5_db_free_principal(kdc_context, princ);
krb5_free_pa_data(kdc_context, e_data);
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index 42b7ee208..04007a8f5 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -76,12 +76,12 @@ get_local_tgt(krb5_context context, const krb5_data *realm,
krb5_db_entry **storage_out, krb5_keyblock *kb_out);
int
-validate_as_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry,
- krb5_db_entry, krb5_timestamp,
+validate_as_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry *,
+ krb5_db_entry *, krb5_timestamp,
const char **, krb5_pa_data ***);
int
-validate_tgs_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry,
+validate_tgs_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry *,
krb5_ticket *, krb5_timestamp,
const char **, krb5_pa_data ***);
diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c
index 554345ba5..3f4fa8499 100644
--- a/src/kdc/tgs_policy.c
+++ b/src/kdc/tgs_policy.c
@@ -48,7 +48,7 @@ struct tgsflagrule {
};
/* Service principal TGS policy checking functions */
-typedef int (check_tgs_svc_pol_fn)(krb5_kdc_req *, krb5_db_entry,
+typedef int (check_tgs_svc_pol_fn)(krb5_kdc_req *, krb5_db_entry *,
krb5_ticket *, krb5_timestamp,
const char **);
@@ -110,7 +110,7 @@ static const struct tgsflagrule svcdenyrules[] = {
* A service principal can forbid some TGS-REQ options.
*/
static int
-check_tgs_svc_deny_opts(krb5_kdc_req *req, krb5_db_entry server,
+check_tgs_svc_deny_opts(krb5_kdc_req *req, krb5_db_entry *server,
krb5_ticket *tkt, krb5_timestamp kdc_time,
const char **status)
{
@@ -122,7 +122,7 @@ check_tgs_svc_deny_opts(krb5_kdc_req *req, krb5_db_entry server,
r = &svcdenyrules[i];
if (!(r->reqflags & req->kdc_options))
continue;
- if (r->checkflag & server.attributes) {
+ if (r->checkflag & server->attributes) {
*status = r->status;
return r->err;
}
@@ -134,20 +134,20 @@ check_tgs_svc_deny_opts(krb5_kdc_req *req, krb5_db_entry server,
* A service principal can deny all TGS-REQs for it.
*/
static int
-check_tgs_svc_deny_all(krb5_kdc_req *req, krb5_db_entry server,
+check_tgs_svc_deny_all(krb5_kdc_req *req, krb5_db_entry *server,
krb5_ticket *tkt, krb5_timestamp kdc_time,
const char **status)
{
- if (server.attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
+ if (server->attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
*status = "SERVER LOCKED OUT";
return KDC_ERR_S_PRINCIPAL_UNKNOWN;
}
- if ((server.attributes & KRB5_KDB_DISALLOW_SVR) &&
+ if ((server->attributes & KRB5_KDB_DISALLOW_SVR) &&
!(req->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY)) {
*status = "SERVER NOT ALLOWED";
return KDC_ERR_MUST_USE_USER2USER;
}
- if (server.attributes & KRB5_KDB_DISALLOW_TGT_BASED) {
+ if (server->attributes & KRB5_KDB_DISALLOW_TGT_BASED) {
if (krb5_is_tgs_principal(tkt->server)) {
*status = "TGT BASED NOT ALLOWED";
return KDC_ERR_POLICY;
@@ -160,17 +160,17 @@ check_tgs_svc_deny_all(krb5_kdc_req *req, krb5_db_entry server,
* A service principal can require certain TGT flags.
*/
static int
-check_tgs_svc_reqd_flags(krb5_kdc_req *req, krb5_db_entry server,
+check_tgs_svc_reqd_flags(krb5_kdc_req *req, krb5_db_entry *server,
krb5_ticket *tkt,
krb5_timestamp kdc_time, const char **status)
{
- if (server.attributes & KRB5_KDB_REQUIRES_HW_AUTH) {
+ if (server->attributes & KRB5_KDB_REQUIRES_HW_AUTH) {
if (!(tkt->enc_part2->flags & TKT_FLG_HW_AUTH)) {
*status = "NO HW PREAUTH";
return KRB_ERR_GENERIC;
}
}
- if (server.attributes & KRB5_KDB_REQUIRES_PRE_AUTH) {
+ if (server->attributes & KRB5_KDB_REQUIRES_PRE_AUTH) {
if (!(tkt->enc_part2->flags & TKT_FLG_PRE_AUTH)) {
*status = "NO PREAUTH";
return KRB_ERR_GENERIC;
@@ -180,10 +180,10 @@ check_tgs_svc_reqd_flags(krb5_kdc_req *req, krb5_db_entry server,
}
static int
-check_tgs_svc_time(krb5_kdc_req *req, krb5_db_entry server, krb5_ticket *tkt,
+check_tgs_svc_time(krb5_kdc_req *req, krb5_db_entry *server, krb5_ticket *tkt,
krb5_timestamp kdc_time, const char **status)
{
- if (server.expiration && ts_after(kdc_time, server.expiration)) {
+ if (server->expiration && ts_after(kdc_time, server->expiration)) {
*status = "SERVICE EXPIRED";
return KDC_ERR_SERVICE_EXP;
}
@@ -191,8 +191,9 @@ check_tgs_svc_time(krb5_kdc_req *req, krb5_db_entry server, krb5_ticket *tkt,
}
static int
-check_tgs_svc_policy(krb5_kdc_req *req, krb5_db_entry server, krb5_ticket *tkt,
- krb5_timestamp kdc_time, const char **status)
+check_tgs_svc_policy(krb5_kdc_req *req, krb5_db_entry *server,
+ krb5_ticket *tkt, krb5_timestamp kdc_time,
+ const char **status)
{
int errcode;
size_t i;
@@ -317,7 +318,7 @@ check_tgs_tgt(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
int
validate_tgs_request(kdc_realm_t *kdc_active_realm,
- krb5_kdc_req *request, krb5_db_entry server,
+ krb5_kdc_req *request, krb5_db_entry *server,
krb5_ticket *ticket, krb5_timestamp kdc_time,
const char **status, krb5_pa_data ***e_data)
{
@@ -367,8 +368,8 @@ validate_tgs_request(kdc_realm_t *kdc_active_realm,
}
/* Perform KDB module policy checks. */
- ret = krb5_db_check_policy_tgs(kdc_context, request, &server,
- ticket, status, e_data);
+ ret = krb5_db_check_policy_tgs(kdc_context, request, server, ticket,
+ status, e_data);
if (ret && ret != KRB5_PLUGIN_OP_NOTSUPP)
return errcode_to_protocol(ret);

View file

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

View file

@ -1,371 +0,0 @@
From c3d2c3bcafe0ac87d9cbbf37f1488ad642627fc3 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 27 May 2020 18:48:35 -0400
Subject: [PATCH] Default dns_canonicalize_hostname to "fallback"
This change should mitigate some of the pain caused by the rdns=true
default (generally associated with unwanted PTR records that cannot
easily be changed), with a minimum of fallout.
Update the documentation and tests accordingly. In test environments,
disable qualify_shortname and use the uncanonicalized system hostname
(lowercased) to match the initial sn2princ result.
ticket: 8911 (new)
---
doc/admin/appl_servers.rst | 14 +++---
doc/admin/conf_files/krb5_conf.rst | 9 ++--
doc/admin/princ_dns.rst | 44 +++++++++++--------
src/kadmin/testing/proto/krb5.conf.proto | 8 ++--
src/kadmin/testing/scripts/env-setup.shin | 4 +-
src/kadmin/testing/scripts/init_db | 3 +-
src/kadmin/testing/scripts/start_servers | 3 +-
.../testing/scripts/start_servers_local | 2 +-
.../kadm5/unit-test/api.current/init-v2.exp | 6 +--
src/lib/krb5/krb/init_ctx.c | 2 +-
src/tests/dejagnu/config/default.exp | 5 +--
src/tests/t_sn2princ.py | 5 ++-
src/util/k5test.py | 25 +++--------
13 files changed, 58 insertions(+), 72 deletions(-)
diff --git a/doc/admin/appl_servers.rst b/doc/admin/appl_servers.rst
index 5232db9af..afdf30297 100644
--- a/doc/admin/appl_servers.rst
+++ b/doc/admin/appl_servers.rst
@@ -115,14 +115,12 @@ Getting DNS information correct
-------------------------------
Several aspects of Kerberos rely on name service. When a hostname is
-used to name a service, the Kerberos library canonicalizes the
-hostname using forward and reverse name resolution. (The reverse name
-resolution step can be turned off using the **rdns** variable in
-:ref:`libdefaults`.) The result of this canonicalization must match
-the principal entry in the host's keytab, or authentication will fail.
-
-Each host's canonical name must be the fully-qualified host name
-(including the domain), and each host's IP address must
+used to name a service, clients may canonicalize the hostname using
+forward and possibly reverse name resolution. The result of this
+canonicalization must match the principal entry in the host's keytab,
+or authentication will fail. To work with all client canonicalization
+configurations, each host's canonical name must be the fully-qualified
+host name (including the domain), and each host's IP address must
reverse-resolve to the canonical name.
Configuration of hostnames varies by operating system. On the
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 3a8b9cf47..38f450367 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -188,11 +188,10 @@ The libdefaults section may contain any of the following relations:
hostnames for use in service principal names. Setting this flag
to false can improve security by reducing reliance on DNS, but
means that short hostnames will not be canonicalized to
- fully-qualified hostnames. The default value is true.
-
- If this option is set to ``fallback`` (new in release 1.18), DNS
- canonicalization will only be performed the server hostname is not
- found with the original name when requesting credentials.
+ fully-qualified hostnames. If this option is set to ``fallback`` (new
+ in release 1.18), DNS canonicalization will only be performed the
+ server hostname is not found with the original name when
+ requesting credentials. The default value is ``fallback``.
**dns_lookup_kdc**
Indicate whether DNS SRV records should be used to locate the KDCs
diff --git a/doc/admin/princ_dns.rst b/doc/admin/princ_dns.rst
index e1d823f27..32a269afc 100644
--- a/doc/admin/princ_dns.rst
+++ b/doc/admin/princ_dns.rst
@@ -31,27 +31,35 @@ based on rotating ``CNAME`` records in DNS.
Service principal canonicalization
----------------------------------
-MIT Kerberos clients currently always do forward resolution (looking
-up the IPv4 and possibly IPv6 addresses using ``getaddrinfo()``) of
-the hostname part of a host-based service principal to canonicalize
-the hostname. They obtain the "canonical" name of the host when doing
-so. By default, MIT Kerberos clients will also then do reverse DNS
-resolution (looking up the hostname associated with the IPv4 or IPv6
-address using ``getnameinfo()``) of the hostname. Using the
-:ref:`krb5.conf(5)` setting::
+In the MIT krb5 client library, canonicalization of host-based service
+principals is controlled by the **dns_canonicalize_hostname**,
+**rnds**, and **qualify_shortname** variables in :ref:`libdefaults`.
- [libdefaults]
- rdns = false
+If **dns_canonicalize_hostname** is set to ``true`` (the default value
+before release 1.19), the client performs forward resolution by
+looking up the IPv4 and/or IPv6 addresses of the hostname using
+``getaddrinfo()``. This process will typically add a domain suffix to
+the hostname if needed, and follow CNAME records in the DNS. If
+**rdns** is also set to ``true`` (the default), the client will then
+perform a reverse lookup of the first returned Internet address using
+``getnameinfo()``, finding the name associated with the PTR record.
-will disable reverse DNS lookup on clients. The default setting is
-"true".
+If **dns_canonicalize_hostname** is set to ``false``, the hostname is
+not canonicalized using DNS. If the hostname has only one component
+(i.e. it contains no "." characters), the host's primary DNS search
+domain will be appended, if there is one. The **qualify_shortname**
+variable can be used to override or disable this suffix.
+
+If **dns_canonicalize_hostname** is set to ``fallback`` (the default
+value in release 1.19 and later), the hostname is initially treated
+according to the rules for ``dns_canonicalize_hostname=false``. If a
+ticket request fails because the service principal is unknown, it the
+hostname will be canonicalized according to the rules for
+``dns_canonicalize_hostname=true`` and the request will be retried.
+
+In all cases, the hostname is converted to lowercase, and any trailing
+dot is removed.
-Operating system bugs may prevent a setting of ``rdns = false`` from
-disabling reverse DNS lookup. Some versions of GNU libc have a bug in
-``getaddrinfo()`` that cause them to look up ``PTR`` records even when
-not required. MIT Kerberos releases krb5-1.10.2 and newer have a
-workaround for this problem, as does the krb5-1.9.x series as of
-release krb5-1.9.4.
Reverse DNS mismatches
diff --git a/src/kadmin/testing/proto/krb5.conf.proto b/src/kadmin/testing/proto/krb5.conf.proto
index e710852d4..c0af716a5 100644
--- a/src/kadmin/testing/proto/krb5.conf.proto
+++ b/src/kadmin/testing/proto/krb5.conf.proto
@@ -2,19 +2,19 @@
default_realm = __REALM__
default_keytab_name = FILE:__K5ROOT__/keytab
dns_fallback = no
+ qualify_shortname = ""
plugin_base_dir = __PLUGIN_DIR__
allow_weak_crypto = true
[realms]
__REALM__ = {
- kdc = __KDCHOST__:1750
- admin_server = __KDCHOST__:1751
+ kdc = __HOSTNAME__:1750
+ admin_server = __HOSTNAME__:1751
database_module = foobar_db2_module_blah
}
[domain_realm]
- __LOCALHOST__ = __REALM__
- __KDCHOST__ = __REALM__
+ __HOSTNAME__ = __REALM__
[logging]
admin_server = FILE:__K5ROOT__/syslog
diff --git a/src/kadmin/testing/scripts/env-setup.shin b/src/kadmin/testing/scripts/env-setup.shin
index 969c5340c..88f8ad1aa 100755
--- a/src/kadmin/testing/scripts/env-setup.shin
+++ b/src/kadmin/testing/scripts/env-setup.shin
@@ -71,8 +71,8 @@ BSDDB_DUMP=$TESTDIR/util/bsddb_dump; export BSDDB_DUMP
CLNTTCL=$TESTDIR/util/kadm5_clnt_tcl; export CLNTTCL
SRVTCL=$TESTDIR/util/kadm5_srv_tcl; export SRVTCL
-QUALNAME=`$BUILDTOP/tests/resolve/resolve -q | tr '[A-Z]' '[a-z]'`
-export QUALNAME
+HOSTNAME=`hostname | tr '[A-Z]' '[a-z]'`
+export HOSTNAME
KRB5_CONFIG=$K5ROOT/krb5.conf; export KRB5_CONFIG
KRB5_KDC_PROFILE=$K5ROOT/kdc.conf; export KRB5_KDC_PROFILE
diff --git a/src/kadmin/testing/scripts/init_db b/src/kadmin/testing/scripts/init_db
index e65826c96..216f62793 100755
--- a/src/kadmin/testing/scripts/init_db
+++ b/src/kadmin/testing/scripts/init_db
@@ -79,8 +79,7 @@ fi
# done
sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
- -e "s/__KDCHOST__/$QUALNAME/g" \
- -e "s/__LOCALHOST__/$QUALNAME/g" \
+ -e "s/__HOSTNAME__/$HOSTNAME/g" \
-e "s#__MODDIR__#$MODDIR#g" \
< $STESTDIR/proto/krb5.conf.proto > $K5ROOT/krb5.conf
sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
diff --git a/src/kadmin/testing/scripts/start_servers b/src/kadmin/testing/scripts/start_servers
index f23df0682..05519e4ee 100755
--- a/src/kadmin/testing/scripts/start_servers
+++ b/src/kadmin/testing/scripts/start_servers
@@ -36,8 +36,7 @@ if [ $local = 0 ]; then
# Fix up the local krb5.conf to point to the remote
sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
- -e "s/__KDCHOST__/$hostname/g" \
- -e "s/__LOCALHOST__/$QUALNAME/g" \
+ -e "s/__HOSTNAME__/$HOSTNAME/g" \
-e "s#__MODDIR__#$TOP/../plugins/kdb#g"\
-e "s#__PLUGIN_DIR__#$TOP/../plugins#g"\
< $STESTDIR/proto/krb5.conf.proto > $K5ROOT/krb5.conf
diff --git a/src/kadmin/testing/scripts/start_servers_local b/src/kadmin/testing/scripts/start_servers_local
index 998ef9164..858e88031 100755
--- a/src/kadmin/testing/scripts/start_servers_local
+++ b/src/kadmin/testing/scripts/start_servers_local
@@ -79,7 +79,7 @@ cat - > /tmp/start_servers_local$$ <<\EOF
if { [catch {
source $env(STOP)/testing/tcl/util.t
set r $env(REALM)
- set q $env(QUALNAME)
+ set q $env(HOSTNAME)
puts stdout [kadm5_init $env(SRVTCL) mrroot null \
[config_params {KADM5_CONFIG_REALM} $r] \
$KADM5_STRUCT_VERSION $KADM5_API_VERSION_3 server_handle]
diff --git a/src/lib/kadm5/unit-test/api.current/init-v2.exp b/src/lib/kadm5/unit-test/api.current/init-v2.exp
index 7a353d4e9..47764c212 100644
--- a/src/lib/kadm5/unit-test/api.current/init-v2.exp
+++ b/src/lib/kadm5/unit-test/api.current/init-v2.exp
@@ -3,18 +3,14 @@ load_lib lib.t
api_exit
api_start
-if ![info exists RESOLVE] {
- set RESOLVE [findfile $objdir/../../../tests/resolve/resolve]
-}
proc get_hostname { } {
- global RESOLVE
global hostname
if {[info exists hostname]} {
return 1
}
- catch "exec $RESOLVE -q >myname" exec_output
+ catch "exec hostname >myname" exec_output
if ![string match "" $exec_output] {
send_log "$exec_output\n"
verbose $exec_output
diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
index 9a4741fa6..0b8ae6714 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -237,7 +237,7 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
ctx->enforce_ok_as_delegate = tmp;
retval = get_tristate(ctx, KRB5_CONF_DNS_CANONICALIZE_HOSTNAME, "fallback",
- CANONHOST_FALLBACK, 1, &tmp);
+ CANONHOST_FALLBACK, CANONHOST_FALLBACK, &tmp);
if (retval)
goto cleanup;
ctx->dns_canonicalize_hostname = tmp;
diff --git a/src/tests/dejagnu/config/default.exp b/src/tests/dejagnu/config/default.exp
index 4d8c917cd..1e7777f1e 100644
--- a/src/tests/dejagnu/config/default.exp
+++ b/src/tests/dejagnu/config/default.exp
@@ -268,7 +268,6 @@ foreach i {
{KTUTIL $objdir/../../kadmin/ktutil/ktutil}
{KLIST $objdir/../../clients/klist/klist}
{KDESTROY $objdir/../../clients/kdestroy/kdestroy}
- {RESOLVE $objdir/../resolve/resolve}
{T_INETD $objdir/t_inetd}
{KPROPLOG $objdir/../../kprop/kproplog}
{KPASSWD $objdir/../../clients/kpasswd/kpasswd}
@@ -462,7 +461,6 @@ proc setup_runtime_env { } {
# 0 on failure.
proc get_hostname { } {
- global RESOLVE
global hostname
global tmppwd
@@ -472,7 +470,7 @@ proc get_hostname { } {
envstack_push
setup_runtime_env
- catch "exec $RESOLVE -q >$tmppwd/hostname" exec_output
+ catch "exec hostname >$tmppwd/hostname" exec_output
envstack_pop
if ![string match "" $exec_output] {
verbose -log $exec_output
@@ -710,6 +708,7 @@ proc setup_krb5_conf { {type client} } {
puts $conffile "\[libdefaults\]"
puts $conffile " default_realm = $REALMNAME"
puts $conffile " dns_lookup_kdc = false"
+ puts $conffile " qualify_shortname = \"\""
if [info exists allow_weak_crypto($type)] {
puts $conffile " allow_weak_crypto = $allow_weak_crypto($type)"
} else {
diff --git a/src/tests/t_sn2princ.py b/src/tests/t_sn2princ.py
index 26dcb91c2..f3e187286 100755
--- a/src/tests/t_sn2princ.py
+++ b/src/tests/t_sn2princ.py
@@ -2,7 +2,8 @@ from k5test import *
offline = (len(args) > 0 and args[0] != "no")
-conf = {'domain_realm': {'kerberos.org': 'R1',
+conf = {'libdefaults': {'dns_canonicalize_hostname': 'true'},
+ 'domain_realm': {'kerberos.org': 'R1',
'example.com': 'R2',
'mit.edu': 'R3'}}
no_rdns_conf = {'libdefaults': {'rdns': 'false'}}
@@ -28,7 +29,7 @@ def testbase(host, nametype, princhost, princrealm, env=None):
fail('Expected %s, got %s' % (expected, out))
def test(host, princhost, princrealm):
- # Test with the host-based name type in the default environment.
+ # Test with the host-based name type with canonicalization enabled.
testbase(host, 'srv-hst', princhost, princrealm)
def testnc(host, princhost, princrealm):
diff --git a/src/util/k5test.py b/src/util/k5test.py
index eea92275d..5196cfa43 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -193,7 +193,10 @@ Scripts may use the following functions and variables:
* plugins: The plugin directory in the build tree (absolute path).
-* hostname: This machine's fully-qualified domain name.
+* hostname: The local hostname as it will initially appear in
+ krb5_sname_to_principal() results. (Shortname qualification is
+ turned off in the test environment to make this value easy to
+ discover from Python.)
* null_input: A file opened to read /dev/null.
@@ -525,23 +528,6 @@ def _find_srctop():
return os.path.abspath(root)
-# Return the local hostname as it will be canonicalized by
-# krb5_sname_to_principal. We can't simply use socket.getfqdn()
-# because it explicitly prefers results containing periods and
-# krb5_sname_to_principal doesn't care.
-def _get_hostname():
- hostname = socket.gethostname()
- try:
- ai = socket.getaddrinfo(hostname, None, 0, 0, 0, socket.AI_CANONNAME)
- except socket.gaierror as e:
- fail('Local hostname "%s" does not resolve: %s.' % (hostname, e[1]))
- (family, socktype, proto, canonname, sockaddr) = ai[0]
- try:
- name = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
- except socket.gaierror:
- return canonname.lower()
- return name[0].lower()
-
# Parse command line arguments, setting global option variables. Also
# sets the global variable args to the positional arguments, which may
# be used by the test script.
@@ -1263,6 +1249,7 @@ _default_krb5_conf = {
'libdefaults': {
'default_realm': '$realm',
'dns_lookup_kdc': 'false',
+ 'qualify_shortname': '',
'plugin_base_dir': '$plugins'},
'realms': {'$realm': {
'kdc': '$hostname:$port0',
@@ -1356,7 +1343,7 @@ buildtop = _find_buildtop()
srctop = _find_srctop()
plugins = os.path.join(buildtop, 'plugins')
runenv = _import_runenv()
-hostname = _get_hostname()
+hostname = socket.gethostname().lower()
null_input = open(os.devnull, 'r')
# A DB pass is a tuple of: name, kdc_conf.

View file

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

View file

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

View file

@ -1,58 +0,0 @@
From 5b42970afea248889fd3350448a40045d467ff3f Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Tue, 28 Jul 2020 12:58:26 -0400
Subject: [PATCH] Fix input length checking in SPNEGO DER decoding
In get_mech_set(), check the length before reading the first byte, and
decrease the length by the tag byte when reading and verifying the
sequence length.
In get_req_flags(), check the length before reading the first byte,
and check the context tag length after decoding it.
ticket: 8933 (new)
tags: pullup
target_version: 1.18-next
target_version: 1.17-next
(cherry picked from commit 64f4b75a22212681ca293f8f09ddd24b0244d5b4)
---
src/lib/gssapi/spnego/spnego_mech.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 4cf011143..13c351620 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -3462,14 +3462,14 @@ get_mech_set(OM_uint32 *minor_status, unsigned char **buff_in,
unsigned char *start;
int i;
- if (**buff_in != SEQUENCE_OF)
+ if (buff_length < 1 || **buff_in != SEQUENCE_OF)
return (NULL);
start = *buff_in;
(*buff_in)++;
- length = gssint_get_der_length(buff_in, buff_length, &bytes);
- if (length < 0 || buff_length - bytes < (unsigned int)length)
+ length = gssint_get_der_length(buff_in, buff_length - 1, &bytes);
+ if (length < 0 || buff_length - 1 - bytes < (unsigned int)length)
return NULL;
major_status = gss_create_empty_oid_set(minor_status,
@@ -3549,11 +3549,11 @@ get_req_flags(unsigned char **buff_in, OM_uint32 bodysize,
{
unsigned int len;
- if (**buff_in != (CONTEXT | 0x01))
+ if (bodysize < 1 || **buff_in != (CONTEXT | 0x01))
return (0);
if (g_get_tag_and_length(buff_in, (CONTEXT | 0x01),
- bodysize, &len) < 0)
+ bodysize, &len) < 0 || len != 4)
return GSS_S_DEFECTIVE_TOKEN;
if (*(*buff_in)++ != BIT_STRING)

View file

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

View file

@ -1,106 +0,0 @@
From c3d96fca46cb2cc3ee9f4c2e2a4ed98bad3e310a Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Thu, 15 Oct 2020 18:15:29 -0400
Subject: [PATCH] Fix minor static analysis defects
Remove an unused variable in krb5_ldap_create(). Handle the return
value from krb5_dbe_get_string() in the certauth test plugin module.
Handle the return value from k5_expand_path_tokens() in
k5_rc_default(). Remove dead assignments in
krb5_get_credentials_for_user() and kg_accept_krb5().
[ghudson@mit.edu: squashed and edited commit message; simplified
k5_rc_default() change]
(cherry picked from commit b27461141810fddd299764928649148c5d0e99f3)
---
src/lib/gssapi/krb5/accept_sec_context.c | 4 +---
src/lib/krb5/krb/s4u_creds.c | 1 -
src/lib/krb5/rcache/rc_base.c | 2 ++
src/plugins/certauth/test/main.c | 3 +++
src/plugins/kdb/ldap/libkdb_ldap/ldap_create.c | 4 ----
5 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 3d5b84b15..e2c5e2b59 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -671,7 +671,7 @@ kg_accept_krb5(minor_status, context_handle,
krb5_auth_context auth_context = NULL;
krb5_ticket * ticket = NULL;
const gss_OID_desc *mech_used = NULL;
- OM_uint32 major_status = GSS_S_FAILURE;
+ OM_uint32 major_status;
OM_uint32 tmp_minor_status;
krb5_error krb_error_data;
krb5_data scratch;
@@ -878,8 +878,6 @@ kg_accept_krb5(minor_status, context_handle,
if (major_status != GSS_S_COMPLETE)
goto fail;
- major_status = GSS_S_FAILURE;
-
if (exts->iakerb.conv && !exts->iakerb.verified) {
major_status = GSS_S_BAD_SIG;
goto fail;
diff --git a/src/lib/krb5/krb/s4u_creds.c b/src/lib/krb5/krb/s4u_creds.c
index d8f486dc6..35a8843e5 100644
--- a/src/lib/krb5/krb/s4u_creds.c
+++ b/src/lib/krb5/krb/s4u_creds.c
@@ -714,7 +714,6 @@ krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
} else if (code != KRB5_CC_NOTFOUND && code != KRB5_CC_NOT_KTYPE) {
goto cleanup;
}
- code = 0;
}
/* Note the authdata we asked for in the output creds. */
diff --git a/src/lib/krb5/rcache/rc_base.c b/src/lib/krb5/rcache/rc_base.c
index 5f456d1f3..f9a482318 100644
--- a/src/lib/krb5/rcache/rc_base.c
+++ b/src/lib/krb5/rcache/rc_base.c
@@ -56,6 +56,8 @@ k5_rc_default(krb5_context context, krb5_rcache *rc_out)
&profstr) == 0 && profstr != NULL) {
ret = k5_expand_path_tokens(context, profstr, &rcname);
profile_release_string(profstr);
+ if (ret)
+ return ret;
ret = k5_rc_resolve(context, rcname, rc_out);
free(rcname);
return ret;
diff --git a/src/plugins/certauth/test/main.c b/src/plugins/certauth/test/main.c
index d4633b8cd..7e7a3ef4c 100644
--- a/src/plugins/certauth/test/main.c
+++ b/src/plugins/certauth/test/main.c
@@ -171,6 +171,9 @@ test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
ret = krb5_dbe_get_string(context, (krb5_db_entry *)db_entry, "hwauth",
&strval);
+ if (ret)
+ goto cleanup;
+
ret = (strval != NULL) ? KRB5_CERTAUTH_HWAUTH : 0;
krb5_dbe_free_string(context, strval);
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_create.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_create.c
index 5b57c799a..2d6605666 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_create.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_create.c
@@ -55,7 +55,6 @@ krb5_ldap_create(krb5_context context, char *conf_section, char **db_args)
krb5_error_code status = 0;
krb5_ldap_realm_params *rparams = NULL;
krb5_ldap_context *ldap_context=NULL;
- krb5_boolean realm_obj_created = FALSE;
int mask = 0;
/* Clear the global error string */
@@ -109,9 +108,6 @@ krb5_ldap_create(krb5_context context, char *conf_section, char **db_args)
if ((status = krb5_ldap_create_realm(context, rparams, mask)))
goto cleanup;
- /* We just created the Realm container. Here starts our transaction tracking */
- realm_obj_created = TRUE;
-
/* verify realm object */
if ((status = krb5_ldap_read_realm_params(context,
rparams->realm_name,

View file

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

View file

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

View file

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

View file

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

View file

@ -1,124 +0,0 @@
From ed87237cdd70f72b309960a294a2bed26cef1579 Mon Sep 17 00:00:00 2001
From: Isaac Boukris <iboukris@gmail.com>
Date: Fri, 4 Sep 2020 14:05:50 +0300
Subject: [PATCH] Improve KDC alias checking for S4U requests
When processing an S4U2Self request, check for DB aliases when
matching the TGT client against the request server. When processing
an S4U2Proxy request, check for DB aliases when matching the TGT
client against the evidence ticket server.
[ghudson@mit.edu: minor edits; rewrote commit message]
ticket: 8946 (new)
(cherry picked from commit 05deeebfc096970b5d9aa67a48b14106cf1b9b56)
---
src/kdc/kdc_util.c | 74 ++++++++++++++++------------------------------
1 file changed, 25 insertions(+), 49 deletions(-)
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index e3352f9cc..dcb2df8dc 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -1463,6 +1463,25 @@ cleanup:
return code;
}
+/* Return true if princ canonicalizes to the same principal as canon. */
+static krb5_boolean
+is_client_alias(krb5_context context, krb5_const_principal canon,
+ krb5_const_principal princ)
+{
+ krb5_error_code ret;
+ krb5_db_entry *self;
+ krb5_boolean is_self = FALSE;
+
+ ret = krb5_db_get_principal(context, princ,
+ KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY, &self);
+ if (!ret) {
+ is_self = krb5_principal_compare(context, canon, self->princ);
+ krb5_db_free_principal(context, self);
+ }
+
+ return is_self;
+}
+
/*
* Protocol transition (S4U2Self)
*/
@@ -1481,7 +1500,6 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
{
krb5_error_code code;
krb5_pa_data *pa_data;
- int flags;
krb5_db_entry *princ;
krb5_s4u_userid *id;
@@ -1515,51 +1533,11 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
}
id = &(*s4u_x509_user)->user_id;
- /*
- * We need to compare the client name in the TGT with the requested
- * server name. Supporting server name aliases without assuming a
- * global name service makes this difficult to do.
- *
- * The comparison below handles the following cases (note that the
- * term "principal name" below excludes the realm).
- *
- * (1) The requested service is a host-based service with two name
- * components, in which case we assume the principal name to
- * contain sufficient qualifying information. The realm is
- * ignored for the purpose of comparison.
- *
- * (2) The requested service name is an enterprise principal name:
- * the service principal name is compared with the unparsed
- * form of the client name (including its realm).
- *
- * (3) The requested service is some other name type: an exact
- * match is required.
- *
- * An alternative would be to look up the server once again with
- * FLAG_CANONICALIZE | FLAG_CLIENT_REFERRALS_ONLY set, do an exact
- * match between the returned name and client_princ. However, this
- * assumes that the client set FLAG_CANONICALIZE when requesting
- * the TGT and that we have a global name service.
- */
- flags = 0;
- switch (krb5_princ_type(kdc_context, request->server)) {
- case KRB5_NT_SRV_HST: /* (1) */
- if (krb5_princ_size(kdc_context, request->server) == 2)
- flags |= KRB5_PRINCIPAL_COMPARE_IGNORE_REALM;
- break;
- case KRB5_NT_ENTERPRISE_PRINCIPAL: /* (2) */
- flags |= KRB5_PRINCIPAL_COMPARE_ENTERPRISE;
- break;
- default: /* (3) */
- break;
- }
-
- if (!krb5_principal_compare_flags(kdc_context,
- request->server,
- client_princ,
- flags)) {
- *status = "INVALID_S4U2SELF_REQUEST";
- return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; /* match Windows error code */
+ /* If the server is local, check that the request is for self. */
+ if (!isflagset(c_flags, KRB5_KDB_FLAG_ISSUING_REFERRAL) &&
+ !is_client_alias(kdc_context, server->princ, client_princ)) {
+ *status = "INVALID_S4U2SELF_REQUEST_SERVER_MISMATCH";
+ return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; /* match Windows error */
}
/*
@@ -1750,9 +1728,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, unsigned int flags,
}
client_princ = *stkt_authdata_client;
- } else if (!krb5_principal_compare(kdc_context,
- server->princ, /* after canon */
- server_princ)) {
+ } else if (!is_client_alias(kdc_context, server->princ, server_princ)) {
*status = "EVIDENCE_TICKET_MISMATCH";
return KRB5KDC_ERR_SERVER_NOMATCH;
}

View file

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

View file

@ -1,316 +0,0 @@
From 5e79319edf3836d12dbc710ec1e2dd4405c9df35 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 25 Sep 2020 11:12:34 -0400
Subject: [PATCH] Minimize usage of tgs_server in KDC
Where possible, use the realm of the request server principal
(canonicalized via KDB lookup, if available) in preference to
tgs_server. This change facilitates alias realm support and potential
future support for serving multiple realms from the same KDB.
S4U2Self local user testing currently uses the uncanonicalized request
realm after this change, which will require attention for alias realm
support.
FAST armor ticket checking is unaffected by this change (it still
compares against tgs_server). This check poses no issue for realm
aliases, as both tgs_server and the armor ticket server should have
canonical realms, but it will require attention for multi-realm KDB
support.
Remove is_local_principal() as it is no longer used. Add an
is_local_tgs_principal() helper and shorten is_cross_tgs_principal().
Move the header ticket lineage check from kdc_process_tgs_req() to
process_tgs_req(), where we have the canonical request server name and
a more natural indication of whether the request was an S4U2Self
request.
(cherry picked from commit 90fedf8188fc47aa5a476a969af34671555df389)
---
src/kdc/do_as_req.c | 21 ++++++--------
src/kdc/do_tgs_req.c | 16 ++++++++---
src/kdc/kdc_util.c | 68 ++++++++++----------------------------------
src/kdc/kdc_util.h | 3 +-
src/kdc/tgs_policy.c | 16 ++++++-----
5 files changed, 46 insertions(+), 78 deletions(-)
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index c2dfea9b8..e0ac33649 100644
--- a/src/kdc/do_as_req.c
+++ b/src/kdc/do_as_req.c
@@ -620,18 +620,6 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
}
state->rock.client = state->client;
- /*
- * If the backend returned a principal that is not in the local
- * realm, then we need to refer the client to that realm.
- */
- if (!is_local_principal(kdc_active_realm, state->client->princ)) {
- /* Entry is a referral to another realm */
- state->status = "REFERRAL";
- au_state->cl_realm = &state->client->princ->realm;
- errcode = KRB5KDC_ERR_WRONG_REALM;
- goto errout;
- }
-
au_state->stage = SRVC_PRINC;
s_flags = 0;
@@ -651,6 +639,15 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
goto errout;
}
+ /* If the KDB module returned a different realm for the client and server,
+ * we need to issue a client realm referral. */
+ if (!data_eq(state->server->princ->realm, state->client->princ->realm)) {
+ state->status = "REFERRAL";
+ au_state->cl_realm = &state->client->princ->realm;
+ errcode = KRB5KDC_ERR_WRONG_REALM;
+ goto errout;
+ }
+
errcode = get_local_tgt(kdc_context, &state->request->server->realm,
state->server, &state->local_tgt,
&state->local_tgt_storage, &state->local_tgt_key);
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index d345797c4..8ea418e43 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -268,7 +268,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
goto cleanup;
}
- if (!is_local_principal(kdc_active_realm, header_ticket->server))
+ if (!data_eq(header_server->princ->realm, sprinc->realm))
setflag(c_flags, KRB5_KDB_FLAG_CROSS_REALM);
if (is_referral)
setflag(c_flags, KRB5_KDB_FLAG_ISSUING_REFERRAL);
@@ -295,6 +295,15 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
au_state->s4u2self_user = NULL;
}
+ /* Aside from cross-realm S4U2Self requests, do not accept header tickets
+ * for local users issued by foreign realms. */
+ if (s4u_x509_user == NULL && data_eq(cprinc->realm, sprinc->realm) &&
+ isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM)) {
+ krb5_klog_syslog(LOG_INFO, _("PROCESS_TGS: failed lineage check"));
+ retval = KRB5KDC_ERR_POLICY;
+ goto cleanup;
+ }
+
if (errcode)
goto cleanup;
@@ -583,13 +592,12 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
/*
* Only add the realm of the presented tgt to the transited list if
- * it is different than the local realm (cross-realm) and it is different
+ * it is different than the server realm (cross-realm) and it is different
* than the realm of the client (since the realm of the client is already
* implicitly part of the transited list and should not be explicitly
* listed).
*/
- /* realm compare is like strcmp, but knows how to deal with these args */
- if (krb5_realm_compare(kdc_context, header_ticket->server, tgs_server) ||
+ if (!isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM) ||
krb5_realm_compare(kdc_context, header_ticket->server,
enc_tkt_reply.client)) {
/* tgt issued by local realm or issued by realm of client */
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index b2042862a..e0b65a87c 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -78,12 +78,6 @@ static krb5_error_code find_server_key(krb5_context,
krb5_kvno, krb5_keyblock **,
krb5_kvno *);
-krb5_boolean
-is_local_principal(kdc_realm_t *kdc_active_realm, krb5_const_principal princ1)
-{
- return krb5_realm_compare(kdc_context, princ1, tgs_server);
-}
-
/*
* Returns TRUE if the kerberos principal is the name of a Kerberos ticket
* service.
@@ -104,13 +98,16 @@ krb5_is_tgs_principal(krb5_const_principal principal)
krb5_boolean
is_cross_tgs_principal(krb5_const_principal principal)
{
- if (!krb5_is_tgs_principal(principal))
- return FALSE;
- if (!data_eq(*krb5_princ_component(kdc_context, principal, 1),
- *krb5_princ_realm(kdc_context, principal)))
- return TRUE;
- else
- return FALSE;
+ return krb5_is_tgs_principal(principal) &&
+ !data_eq(principal->data[1], principal->realm);
+}
+
+/* Return true if princ is the name of a local TGS for any realm. */
+krb5_boolean
+is_local_tgs_principal(krb5_const_principal principal)
+{
+ return krb5_is_tgs_principal(principal) &&
+ data_eq(principal->data[1], principal->realm);
}
/*
@@ -143,17 +140,6 @@ comp_cksum(krb5_context kcontext, krb5_data *source, krb5_ticket *ticket,
return(0);
}
-/* Return true if padata contains an entry of either S4U2Self type. */
-static inline krb5_boolean
-has_s4u2self_padata(krb5_pa_data **padata)
-{
- if (krb5int_find_pa_data(NULL, padata, KRB5_PADATA_FOR_USER) != NULL)
- return TRUE;
- if (krb5int_find_pa_data(NULL, padata, KRB5_PADATA_S4U_X509_USER) != NULL)
- return TRUE;
- return FALSE;
-}
-
/* If a header ticket is decrypted, *ticket_out is filled in even on error. */
krb5_error_code
kdc_process_tgs_req(kdc_realm_t *kdc_active_realm,
@@ -170,7 +156,6 @@ kdc_process_tgs_req(kdc_realm_t *kdc_active_realm,
krb5_authdata **authdata = NULL;
krb5_data scratch1;
krb5_data * scratch = NULL;
- krb5_boolean foreign_server = FALSE;
krb5_auth_context auth_context = NULL;
krb5_authenticator * authenticator = NULL;
krb5_checksum * his_cksum = NULL;
@@ -199,19 +184,6 @@ kdc_process_tgs_req(kdc_realm_t *kdc_active_realm,
goto cleanup;
}
- /* If the "server" principal in the ticket is not something
- in the local realm, then we must refuse to service the request
- if the client claims to be from the local realm.
-
- If we don't do this, then some other realm's nasty KDC can
- claim to be authenticating a client from our realm, and we'll
- give out tickets concurring with it!
-
- we set a flag here for checking below.
- */
- foreign_server = !is_local_principal(kdc_active_realm,
- apreq->ticket->server);
-
if ((retval = krb5_auth_con_init(kdc_context, &auth_context)))
goto cleanup;
@@ -265,15 +237,6 @@ kdc_process_tgs_req(kdc_realm_t *kdc_active_realm,
goto cleanup_authenticator;
}
- /* make sure the client is of proper lineage (see above) */
- if (foreign_server && !has_s4u2self_padata(request->padata) &&
- is_local_principal(kdc_active_realm, ticket->enc_part2->client)) {
- /* someone in a foreign realm claiming to be local */
- krb5_klog_syslog(LOG_INFO, _("PROCESS_TGS: failed lineage check"));
- retval = KRB5KDC_ERR_POLICY;
- goto cleanup_authenticator;
- }
-
/*
* Check application checksum vs. tgs request
*
@@ -591,12 +554,12 @@ int
check_anon(kdc_realm_t *kdc_active_realm,
krb5_principal client, krb5_principal server)
{
- /* If restrict_anon is set, reject requests from anonymous to principals
- * other than the local TGT. */
+ /* If restrict_anon is set, reject requests from anonymous clients to
+ * server principals other than local TGTs. */
if (kdc_active_realm->realm_restrict_anon &&
krb5_principal_compare_any_realm(kdc_context, client,
krb5_anonymous_principal()) &&
- !krb5_principal_compare(kdc_context, server, tgs_server))
+ !is_local_tgs_principal(server))
return -1;
return 0;
}
@@ -1527,7 +1490,7 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
/*
* Do not attempt to lookup principals in foreign realms.
*/
- if (is_local_principal(kdc_active_realm, id->user)) {
+ if (data_eq(server->princ->realm, id->user->realm)) {
krb5_db_entry no_server;
krb5_pa_data **e_data = NULL;
@@ -1663,8 +1626,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, unsigned int flags,
*/
if (isflagset(flags, KRB5_KDB_FLAG_ISSUING_REFERRAL) ||
!is_cross_tgs_principal(server->princ) ||
- !krb5_principal_compare_any_realm(kdc_context, server->princ,
- tgs_server) ||
+ !data_eq(server->princ->data[1], proxy->princ->realm) ||
!krb5_principal_compare(kdc_context, client_princ, server_princ)) {
*status = "XREALM_EVIDENCE_TICKET_MISMATCH";
return KRB5KDC_ERR_BADOPTION;
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index 04007a8f5..a6bac4388 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -37,10 +37,9 @@
#include "reqstate.h"
krb5_error_code check_hot_list (krb5_ticket *);
-krb5_boolean is_local_principal(kdc_realm_t *kdc_active_realm,
- krb5_const_principal princ1);
krb5_boolean krb5_is_tgs_principal (krb5_const_principal);
krb5_boolean is_cross_tgs_principal(krb5_const_principal);
+krb5_boolean is_local_tgs_principal(krb5_const_principal);
krb5_error_code
add_to_transited (krb5_data *,
krb5_data *,
diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c
index 3f4fa8499..a5a00f0cc 100644
--- a/src/kdc/tgs_policy.c
+++ b/src/kdc/tgs_policy.c
@@ -252,19 +252,21 @@ check_tgs_s4u2proxy(kdc_realm_t *kdc_active_realm,
}
static int
-check_tgs_u2u(kdc_realm_t *kdc_active_realm,
- krb5_kdc_req *req, const char **status)
+check_tgs_u2u(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
+ krb5_const_principal server_princ, const char **status)
{
+ krb5_const_principal second_server_princ;
+
if (req->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
/* Check that second ticket is in request. */
if (!req->second_ticket || !req->second_ticket[0]) {
*status = "NO_2ND_TKT";
return KDC_ERR_BADOPTION;
}
- /* Check that second ticket is a TGT. */
- if (!krb5_principal_compare(kdc_context,
- req->second_ticket[0]->server,
- tgs_server)) {
+ /* Check that second ticket is a TGT to the server realm. */
+ second_server_princ = req->second_ticket[0]->server;
+ if (!is_local_tgs_principal(second_server_princ) ||
+ !data_eq(second_server_princ->data[1], server_princ->realm)) {
*status = "2ND_TKT_NOT_TGS";
return KDC_ERR_POLICY;
}
@@ -353,7 +355,7 @@ validate_tgs_request(kdc_realm_t *kdc_active_realm,
return(KRB_AP_ERR_REPEAT);
}
- errcode = check_tgs_u2u(kdc_active_realm, request, status);
+ errcode = check_tgs_u2u(kdc_active_realm, request, server->princ, status);
if (errcode != 0)
return errcode;

View file

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

View file

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

View file

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

View file

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

View file

@ -1,335 +0,0 @@
From 9335481c00cd15170adec244ccff0a00a014bbab Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 5 Feb 2020 18:46:11 -0500
Subject: [PATCH] Refactor KDC authdata list management helpers
Remove the unused concat_authorization_data(). Split merge_authdata()
into two helpers, one to destructively merge without filtering and one
to add copied elements while filtering out KDC-only authdata types.
Remove context parameters where they aren't needed (taking advantage
of knowledge that some libkrb5 functions don't use their context
parameters).
(cherry picked from commit b2190fdc253de6024001e0f1ff9fe56c31042bb7)
---
src/kdc/kdc_authdata.c | 138 +++++++++++++++++++----------------------
src/kdc/kdc_util.c | 50 ---------------
src/kdc/kdc_util.h | 5 --
3 files changed, 64 insertions(+), 129 deletions(-)
diff --git a/src/kdc/kdc_authdata.c b/src/kdc/kdc_authdata.c
index 1ebe87246..010922c27 100644
--- a/src/kdc/kdc_authdata.c
+++ b/src/kdc/kdc_authdata.c
@@ -108,7 +108,7 @@ unload_authdata_plugins(krb5_context context)
/* Return true if authdata should be filtered when copying from untrusted
* authdata. If desired_type is non-zero, look only for that type. */
static krb5_boolean
-is_kdc_issued_authdatum(krb5_context context, krb5_authdata *authdata,
+is_kdc_issued_authdatum(krb5_authdata *authdata,
krb5_authdatatype desired_type)
{
krb5_boolean result = FALSE;
@@ -117,7 +117,7 @@ is_kdc_issued_authdatum(krb5_context context, krb5_authdata *authdata,
krb5_authdatatype *ad_types, *containee_types = NULL;
if (authdata->ad_type == KRB5_AUTHDATA_IF_RELEVANT) {
- if (krb5int_get_authdata_containee_types(context, authdata, &count,
+ if (krb5int_get_authdata_containee_types(NULL, authdata, &count,
&containee_types) != 0)
goto cleanup;
ad_types = containee_types;
@@ -152,7 +152,7 @@ cleanup:
/* Return true if authdata contains any elements which should only come from
* the KDC. If desired_type is non-zero, look only for that type. */
static krb5_boolean
-has_kdc_issued_authdata(krb5_context context, krb5_authdata **authdata,
+has_kdc_issued_authdata(krb5_authdata **authdata,
krb5_authdatatype desired_type)
{
int i;
@@ -160,7 +160,7 @@ has_kdc_issued_authdata(krb5_context context, krb5_authdata **authdata,
if (authdata == NULL)
return FALSE;
for (i = 0; authdata[i] != NULL; i++) {
- if (is_kdc_issued_authdatum(context, authdata[i], desired_type))
+ if (is_kdc_issued_authdatum(authdata[i], desired_type))
return TRUE;
}
return FALSE;
@@ -181,66 +181,71 @@ has_mandatory_for_kdc_authdata(krb5_context context, krb5_authdata **authdata)
return FALSE;
}
-/*
- * Add the elements of in_authdata to out_authdata. If copy is false,
- * in_authdata is invalid on successful return. If ignore_kdc_issued is true,
- * KDC-issued authdata is not copied.
- */
+/* Add elements from *new_elements to *existing_list, reallocating as
+ * necessary. On success, release *new_elements and set it to NULL. */
static krb5_error_code
-merge_authdata(krb5_context context, krb5_authdata **in_authdata,
- krb5_authdata ***out_authdata, krb5_boolean copy,
- krb5_boolean ignore_kdc_issued)
+merge_authdata(krb5_authdata ***existing_list, krb5_authdata ***new_elements)
{
- krb5_error_code ret;
- size_t i, j, nadata = 0;
- krb5_authdata **in_copy = NULL, **authdata = *out_authdata;
+ size_t count = 0, ncount = 0;
+ krb5_authdata **list = *existing_list, **nlist = *new_elements;
- if (in_authdata == NULL || in_authdata[0] == NULL)
+ if (nlist == NULL)
return 0;
- if (authdata != NULL) {
- for (nadata = 0; authdata[nadata] != NULL; nadata++)
- ;
- }
+ for (count = 0; list != NULL && list[count] != NULL; count++);
+ for (ncount = 0; nlist[ncount] != NULL; ncount++);
- for (i = 0; in_authdata[i] != NULL; i++)
- ;
-
- if (copy) {
- ret = krb5_copy_authdata(context, in_authdata, &in_copy);
- if (ret)
- return ret;
- in_authdata = in_copy;
- }
-
- authdata = realloc(authdata, (nadata + i + 1) * sizeof(krb5_authdata *));
- if (authdata == NULL) {
- krb5_free_authdata(context, in_copy);
+ list = realloc(list, (count + ncount + 1) * sizeof(*list));
+ if (list == NULL)
return ENOMEM;
+
+ memcpy(list + count, nlist, ncount * sizeof(*nlist));
+ list[count + ncount] = NULL;
+ free(nlist);
+
+ if (list[0] == NULL) {
+ free(list);
+ list = NULL;
}
- for (i = 0, j = 0; in_authdata[i] != NULL; i++) {
- if (ignore_kdc_issued &&
- is_kdc_issued_authdatum(context, in_authdata[i], 0)) {
- free(in_authdata[i]->contents);
- free(in_authdata[i]);
+ *new_elements = NULL;
+ *existing_list = list;
+ return 0;
+}
+
+/* Add a copy of new_elements to *existing_list, omitting KDC-issued
+ * authdata. */
+static krb5_error_code
+add_filtered_authdata(krb5_authdata ***existing_list,
+ krb5_authdata **new_elements)
+{
+ krb5_error_code ret;
+ krb5_authdata **copy;
+ size_t i, j;
+
+ if (new_elements == NULL)
+ return 0;
+
+ ret = krb5_copy_authdata(NULL, new_elements, &copy);
+ if (ret)
+ return ret;
+
+ /* Remove KDC-issued elements from copy. */
+ j = 0;
+ for (i = 0; copy[i] != NULL; i++) {
+ if (is_kdc_issued_authdatum(copy[i], 0)) {
+ free(copy[i]->contents);
+ free(copy[i]);
} else {
- authdata[nadata + j++] = in_authdata[i];
+ copy[j++] = copy[i];
}
}
+ copy[j] = NULL;
- authdata[nadata + j] = NULL;
-
- free(in_authdata);
-
- if (authdata[0] == NULL) {
- free(authdata);
- authdata = NULL;
- }
-
- *out_authdata = authdata;
-
- return 0;
+ /* Destructively merge the filtered copy into existing_list. */
+ ret = merge_authdata(existing_list, &copy);
+ krb5_free_authdata(NULL, copy);
+ return ret;
}
/* Copy TGS-REQ authorization data into the ticket authdata. */
@@ -289,10 +294,7 @@ copy_request_authdata(krb5_context context, krb5_keyblock *client_key,
goto cleanup;
}
- /* Add a copy of the requested authdata to the ticket, ignoring KDC-issued
- * types. */
- ret = merge_authdata(context, req->unenc_authdata, tkt_authdata, TRUE,
- TRUE);
+ ret = add_filtered_authdata(tkt_authdata, req->unenc_authdata);
cleanup:
free(plaintext.data);
@@ -307,9 +309,7 @@ copy_tgt_authdata(krb5_context context, krb5_kdc_req *request,
if (has_mandatory_for_kdc_authdata(context, tgt_authdata))
return KRB5KDC_ERR_POLICY;
- /* Add a copy of the TGT authdata to the ticket, ignoring KDC-issued
- * types. */
- return merge_authdata(context, tgt_authdata, tkt_authdata, TRUE, TRUE);
+ return add_filtered_authdata(tkt_authdata, tgt_authdata);
}
/* Fetch authorization data from KDB module. */
@@ -374,8 +374,7 @@ fetch_kdb_authdata(krb5_context context, unsigned int flags,
/* Put the KDB authdata first in the ticket. A successful merge places the
* combined list in db_authdata and releases the old ticket authdata. */
- ret = merge_authdata(context, enc_tkt_reply->authorization_data,
- &db_authdata, FALSE, FALSE);
+ ret = merge_authdata(&db_authdata, &enc_tkt_reply->authorization_data);
if (ret)
krb5_free_authdata(context, db_authdata);
else
@@ -404,8 +403,7 @@ make_signedpath_data(krb5_context context, krb5_const_principal client,
return ret;
for (i = 0, j = 0; authdata[i] != NULL; i++) {
- if (is_kdc_issued_authdatum(context, authdata[i],
- KRB5_AUTHDATA_SIGNTICKET))
+ if (is_kdc_issued_authdatum(authdata[i], KRB5_AUTHDATA_SIGNTICKET))
continue;
sign_authdata[j++] = authdata[i];
@@ -635,12 +633,8 @@ make_signedpath(krb5_context context, krb5_const_principal for_user_princ,
if (ret)
goto cleanup;
- /* Add the authdata to the ticket, without copying or filtering. */
- ret = merge_authdata(context, if_relevant,
- &enc_tkt_reply->authorization_data, FALSE, FALSE);
- if (ret)
- goto cleanup;
- if_relevant = NULL; /* merge_authdata() freed */
+ /* Add the signedpath authdata to the ticket. */
+ ret = merge_authdata(&enc_tkt_reply->authorization_data, &if_relevant);
cleanup:
free(sp.delegated);
@@ -665,7 +659,7 @@ free_deleg_path(krb5_context context, krb5_principal *deleg_path)
static krb5_boolean
has_pac(krb5_context context, krb5_authdata **authdata)
{
- return has_kdc_issued_authdata(context, authdata, KRB5_AUTHDATA_WIN2K_PAC);
+ return has_kdc_issued_authdata(authdata, KRB5_AUTHDATA_WIN2K_PAC);
}
/* Verify AD-SIGNTICKET authdata if we need to, and insert an AD-SIGNEDPATH
@@ -746,11 +740,7 @@ add_auth_indicators(krb5_context context, krb5_data *const *auth_indicators,
goto cleanup;
/* Add the wrapped authdata to the ticket, without copying or filtering. */
- ret = merge_authdata(context, cammac, &enc_tkt_reply->authorization_data,
- FALSE, FALSE);
- if (ret)
- goto cleanup;
- cammac = NULL; /* merge_authdata() freed */
+ ret = merge_authdata(&enc_tkt_reply->authorization_data, &cammac);
cleanup:
krb5_free_data(context, der_indicators);
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index 6330387d0..a4a05b9fa 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -78,56 +78,6 @@ static krb5_error_code find_server_key(krb5_context,
krb5_kvno, krb5_keyblock **,
krb5_kvno *);
-/*
- * concatenate first two authdata arrays, returning an allocated replacement.
- * The replacement should be freed with krb5_free_authdata().
- */
-krb5_error_code
-concat_authorization_data(krb5_context context,
- krb5_authdata **first, krb5_authdata **second,
- krb5_authdata ***output)
-{
- int i, j;
- krb5_authdata **ptr, **retdata;
-
- /* count up the entries */
- i = 0;
- if (first)
- for (ptr = first; *ptr; ptr++)
- i++;
- if (second)
- for (ptr = second; *ptr; ptr++)
- i++;
-
- retdata = (krb5_authdata **)malloc((i+1)*sizeof(*retdata));
- if (!retdata)
- return ENOMEM;
- retdata[i] = 0; /* null-terminated array */
- for (i = 0, j = 0, ptr = first; j < 2 ; ptr = second, j++)
- while (ptr && *ptr) {
- /* now walk & copy */
- retdata[i] = (krb5_authdata *)malloc(sizeof(*retdata[i]));
- if (!retdata[i]) {
- krb5_free_authdata(context, retdata);
- return ENOMEM;
- }
- *retdata[i] = **ptr;
- if (!(retdata[i]->contents =
- (krb5_octet *)malloc(retdata[i]->length))) {
- free(retdata[i]);
- retdata[i] = 0;
- krb5_free_authdata(context, retdata);
- return ENOMEM;
- }
- memcpy(retdata[i]->contents, (*ptr)->contents, retdata[i]->length);
-
- ptr++;
- i++;
- }
- *output = retdata;
- return 0;
-}
-
krb5_boolean
is_local_principal(kdc_realm_t *kdc_active_realm, krb5_const_principal princ1)
{
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index 2c9d8cf69..42b7ee208 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -52,11 +52,6 @@ compress_transited (krb5_data *,
krb5_principal,
krb5_data *);
krb5_error_code
-concat_authorization_data (krb5_context,
- krb5_authdata **,
- krb5_authdata **,
- krb5_authdata ***);
-krb5_error_code
fetch_last_req_info (krb5_db_entry *, krb5_last_req_entry ***);
krb5_error_code

View file

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

View file

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

View file

@ -1,547 +0,0 @@
From 3e75969e0c0a52ec3ca8195200fcdadaa63b324f Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Thu, 28 May 2020 18:41:02 -0400
Subject: [PATCH] Remove resolver test utility
tests/resolve is no longer used after the previous commit.
[rharwood@redhat.com: .gitignore]
---
src/configure.ac | 5 +-
src/tests/Makefile.in | 4 +-
src/tests/resolve/Makefile.in | 28 ---
src/tests/resolve/addrinfo-test.c | 306 -------------------------
src/tests/resolve/deps | 14 --
src/tests/resolve/fake-addrinfo-test.c | 3 -
src/tests/resolve/resolve.c | 115 ----------
7 files changed, 4 insertions(+), 471 deletions(-)
delete mode 100644 src/tests/resolve/Makefile.in
delete mode 100644 src/tests/resolve/addrinfo-test.c
delete mode 100644 src/tests/resolve/deps
delete mode 100644 src/tests/resolve/fake-addrinfo-test.c
delete mode 100644 src/tests/resolve/resolve.c
diff --git a/src/configure.ac b/src/configure.ac
index aafc462f9..00b5ea4c5 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1540,7 +1540,6 @@ V5_AC_OUTPUT_MAKEFILE(.
appl/simple appl/simple/client appl/simple/server
appl/gss-sample appl/user_user
- tests tests/resolve tests/asn.1 tests/create tests/hammer
- tests/verify tests/gssapi tests/dejagnu tests/threads tests/shlib
- tests/gss-threads tests/misc
+ tests tests/asn.1 tests/create tests/hammer tests/verify tests/gssapi
+ tests/dejagnu tests/threads tests/shlib tests/gss-threads tests/misc
)
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 3f88f1713..6b7749129 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -1,7 +1,7 @@
mydir=tests
BUILDTOP=$(REL)..
-SUBDIRS = resolve asn.1 create hammer verify gssapi dejagnu shlib \
- gss-threads misc threads softpkcs11
+SUBDIRS = asn.1 create hammer verify gssapi dejagnu shlib gss-threads misc \
+ threads softpkcs11
RUN_DB_TEST = $(RUN_SETUP) KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf \
GSS_MECH_CONFIG=mech.conf LC_ALL=C $(VALGRIND)
diff --git a/src/tests/resolve/Makefile.in b/src/tests/resolve/Makefile.in
deleted file mode 100644
index 1f5954089..000000000
--- a/src/tests/resolve/Makefile.in
+++ /dev/null
@@ -1,28 +0,0 @@
-mydir=tests$(S)resolve
-BUILDTOP=$(REL)..$(S)..
-
-OBJS=resolve.o addrinfo-test.o fake-addrinfo-test.o
-SRCS=$(srcdir)/resolve.c $(srcdir)/addrinfo-test.c \
- $(srcdir)/fake-addrinfo-test.c
-
-all: resolve addrinfo-test fake-addrinfo-test
-
-resolve: resolve.o
- $(CC_LINK) -o $@ resolve.o $(SUPPORT_LIB) $(LIBS)
-
-addrinfo-test: addrinfo-test.o
- $(CC_LINK) -o $@ addrinfo-test.o $(SUPPORT_LIB) $(LIBS)
-
-fake-addrinfo-test: fake-addrinfo-test.o
- $(CC_LINK) -o $@ fake-addrinfo-test.o $(SUPPORT_LIB) $(LIBS)
-
-check: resolve addrinfo-test fake-addrinfo-test
- $(RUN_TEST) ./resolve
- $(RUN_TEST) ./addrinfo-test -p telnet
- $(RUN_TEST) ./fake-addrinfo-test -p telnet
-
-install:
-
-clean:
- $(RM) resolve addrinfo-test fake-addrinfo-test
-
diff --git a/src/tests/resolve/addrinfo-test.c b/src/tests/resolve/addrinfo-test.c
deleted file mode 100644
index e77640b62..000000000
--- a/src/tests/resolve/addrinfo-test.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* tests/resolve/addrinfo-test.c */
-/*
- * Copyright 2004 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * A simple program to test the functionality of the getaddrinfo function.
- *
- * Usage:
- * addrinfo-test [-t|-u|-R|-I] [-d|-s|-r] [-p port] [-P] [hostname]
- *
- * When invoked with no arguments, NULL is used for the node name,
- * which (at least with a non-null "port") means a socket address
- * is desired that can be used with connect() or bind() (depending
- * on whether "-P" is given).
- */
-
-#include <k5-platform.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h> /* needed for IPPROTO_* on NetBSD */
-#ifdef USE_FAKE_ADDRINFO
-#include "fake-addrinfo.h"
-#endif
-
-static const char *protoname (int p) {
- static char buf[30];
-
-#define X(N) if (p == IPPROTO_ ## N) return #N
-
- X(TCP);
- X(UDP);
- X(ICMP);
-#ifdef IPPROTO_IPV6
- X(IPV6);
-#endif
-#ifdef IPPROTO_GRE
- X(GRE);
-#endif
-#ifdef IPPROTO_NONE
- X(NONE);
-#endif
- X(RAW);
-#ifdef IPPROTO_COMP
- X(COMP);
-#endif
-
- snprintf(buf, sizeof(buf), " %-2d", p);
- return buf;
-}
-
-static const char *socktypename (int t) {
- static char buf[30];
- switch (t) {
- case SOCK_DGRAM: return "DGRAM";
- case SOCK_STREAM: return "STREAM";
- case SOCK_RAW: return "RAW";
- case SOCK_RDM: return "RDM";
- case SOCK_SEQPACKET: return "SEQPACKET";
- }
- snprintf(buf, sizeof(buf), " %-2d", t);
- return buf;
-}
-
-static char *whoami;
-
-static void usage () {
- fprintf(stderr,
- "usage:\n"
- "\t%s [ options ] [host]\n"
- "options:\n"
- "\t-t\tspecify protocol IPPROTO_TCP\n"
- "\t-u\tspecify protocol IPPROTO_UDP\n"
- "\t-R\tspecify protocol IPPROTO_RAW\n"
- "\t-I\tspecify protocol IPPROTO_ICMP\n"
- "\n"
- "\t-d\tspecify socket type SOCK_DGRAM\n"
- "\t-s\tspecify socket type SOCK_STREAM\n"
- "\t-r\tspecify socket type SOCK_RAW\n"
- "\n"
- "\t-4\tspecify address family AF_INET\n"
-#ifdef AF_INET6
- "\t-6\tspecify address family AF_INET6\n"
-#endif
- "\n"
- "\t-p P\tspecify port P (service name or port number)\n"
- "\t-N\thostname is numeric, skip DNS query\n"
- "\t-n\tservice/port is numeric (sets AI_NUMERICSERV)\n"
- "\t-P\tset AI_PASSIVE\n"
- "\n"
- "default: protocol 0, socket type 0, address family 0, null port\n"
- ,
- whoami);
- /* [ -t | -u | -R | -I ] [ -d | -s | -r ] [ -p port ] */
- exit (1);
-}
-
-static const char *familyname (int f) {
- static char buf[30];
- switch (f) {
- default:
- snprintf(buf, sizeof(buf), "AF %d", f);
- return buf;
- case AF_INET: return "AF_INET";
-#ifdef AF_INET6
- case AF_INET6: return "AF_INET6";
-#endif
- }
-}
-
-#define eaistr(X) (X == EAI_SYSTEM ? strerror(errno) : gai_strerror(X))
-
-int main (int argc, char *argv[])
-{
- struct addrinfo *ap, *ap2;
- int err, numerichost = 0, numericserv = 0;
- char *hname, *port = 0, *sep;
- struct addrinfo hints;
-
- whoami = strrchr(argv[0], '/');
- if (whoami == 0)
- whoami = argv[0];
- else
- whoami = whoami+1;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = 0;
- hints.ai_socktype = 0;
-
- hname = 0;
- hints.ai_family = 0;
-
- if (argc == 1)
- usage ();
-
- while (++argv, --argc > 0) {
- char *arg;
- arg = *argv;
-
- if (*arg != '-')
- hname = arg;
- else if (arg[1] == 0 || arg[2] != 0)
- usage ();
- else
- switch (arg[1]) {
- case 'u':
- hints.ai_protocol = IPPROTO_UDP;
- break;
- case 't':
- hints.ai_protocol = IPPROTO_TCP;
- break;
- case 'R':
- hints.ai_protocol = IPPROTO_RAW;
- break;
- case 'I':
- hints.ai_protocol = IPPROTO_ICMP;
- break;
- case 'd':
- hints.ai_socktype = SOCK_DGRAM;
- break;
- case 's':
- hints.ai_socktype = SOCK_STREAM;
- break;
- case 'r':
- hints.ai_socktype = SOCK_RAW;
- break;
- case 'p':
- if (argv[1] == 0 || argv[1][0] == 0 || argv[1][0] == '-')
- usage ();
- port = argv[1];
- argc--, argv++;
- break;
- case '4':
- hints.ai_family = AF_INET;
- break;
-#ifdef AF_INET6
- case '6':
- hints.ai_family = AF_INET6;
- break;
-#endif
- case 'N':
- numerichost = 1;
- break;
- case 'n':
- numericserv = 1;
- break;
- case 'P':
- hints.ai_flags |= AI_PASSIVE;
- break;
- default:
- usage ();
- }
- }
-
- if (hname && !numerichost)
- hints.ai_flags |= AI_CANONNAME;
- if (numerichost) {
-#ifdef AI_NUMERICHOST
- hints.ai_flags |= AI_NUMERICHOST;
-#else
- fprintf(stderr, "AI_NUMERICHOST not defined on this platform\n");
- exit(1);
-#endif
- }
- if (numericserv) {
-#ifdef AI_NUMERICSERV
- hints.ai_flags |= AI_NUMERICSERV;
-#else
- fprintf(stderr, "AI_NUMERICSERV not defined on this platform\n");
- exit(1);
-#endif
- }
-
- printf("getaddrinfo(hostname %s, service %s,\n"
- " hints { ",
- hname ? hname : "(null)", port ? port : "(null)");
- sep = "";
-#define Z(FLAG) if (hints.ai_flags & AI_##FLAG) printf("%s%s", sep, #FLAG), sep = "|"
- Z(CANONNAME);
- Z(PASSIVE);
-#ifdef AI_NUMERICHOST
- Z(NUMERICHOST);
-#endif
-#ifdef AI_NUMERICSERV
- Z(NUMERICSERV);
-#endif
- if (sep[0] == 0)
- printf ("no-flags");
- if (hints.ai_family)
- printf(" %s", familyname(hints.ai_family));
- if (hints.ai_socktype)
- printf(" SOCK_%s", socktypename(hints.ai_socktype));
- if (hints.ai_protocol)
- printf(" IPPROTO_%s", protoname(hints.ai_protocol));
- printf(" }):\n");
-
- err = getaddrinfo(hname, port, &hints, &ap);
- if (err) {
- printf("\terror => %s\n", eaistr(err));
- return 1;
- }
-
- for (ap2 = ap; ap2; ap2 = ap2->ai_next) {
- char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
- /* If we don't do this, even AIX's own getnameinfo will reject
- the sockaddr structures. The sa_len field doesn't get set
- either, on AIX, but getnameinfo won't complain. */
- if (ap2->ai_addr->sa_family == 0) {
- printf("BAD: sa_family zero! fixing...\n");
- ap2->ai_addr->sa_family = ap2->ai_family;
- } else if (ap2->ai_addr->sa_family != ap2->ai_family) {
- printf("BAD: sa_family != ai_family! fixing...\n");
- ap2->ai_addr->sa_family = ap2->ai_family;
- }
- if (getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof(hbuf),
- pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
- strlcpy(hbuf, "...", sizeof(hbuf));
- strlcpy(pbuf, "...", sizeof(pbuf));
- }
- printf("%p:\n"
- "\tfamily = %s\tproto = %-4s\tsocktype = %s\n",
- (void *) ap2, familyname(ap2->ai_family),
- protoname (ap2->ai_protocol),
- socktypename (ap2->ai_socktype));
- if (ap2->ai_canonname) {
- if (ap2->ai_canonname[0])
- printf("\tcanonname = %s\n", ap2->ai_canonname);
- else
- printf("BAD: ai_canonname is set but empty!\n");
- } else if (ap2 == ap && (hints.ai_flags & AI_CANONNAME)) {
- printf("BAD: first ai_canonname is null!\n");
- }
- printf("\taddr = %-28s\tport = %s\n", hbuf, pbuf);
-
- err = getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof (hbuf),
- pbuf, sizeof(pbuf), NI_NAMEREQD);
- if (err)
- printf("\tgetnameinfo(NI_NAMEREQD): %s\n", eaistr(err));
- else
- printf("\tgetnameinfo => %s, %s\n", hbuf, pbuf);
- }
- freeaddrinfo(ap);
- return 0;
-}
diff --git a/src/tests/resolve/deps b/src/tests/resolve/deps
deleted file mode 100644
index 762d9adab..000000000
--- a/src/tests/resolve/deps
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Generated makefile dependencies follow.
-#
-$(OUTPRE)resolve.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
- $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
- resolve.c
-$(OUTPRE)addrinfo-test.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
- $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
- addrinfo-test.c
-$(OUTPRE)fake-addrinfo-test.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
- $(top_srcdir)/include/fake-addrinfo.h $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/port-sockets.h \
- $(top_srcdir)/include/socket-utils.h addrinfo-test.c \
- fake-addrinfo-test.c
diff --git a/src/tests/resolve/fake-addrinfo-test.c b/src/tests/resolve/fake-addrinfo-test.c
deleted file mode 100644
index 86365a5ba..000000000
--- a/src/tests/resolve/fake-addrinfo-test.c
+++ /dev/null
@@ -1,3 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-#define USE_FAKE_ADDRINFO
-#include "addrinfo-test.c"
diff --git a/src/tests/resolve/resolve.c b/src/tests/resolve/resolve.c
deleted file mode 100644
index ea0239113..000000000
--- a/src/tests/resolve/resolve.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* tests/resolve/resolve.c */
-/*
- * Copyright 1995 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * A simple program to test the functionality of the resolver library.
- * It simply will try to get the IP address of the host, and then look
- * up the name from the address. If the resulting name does not contain the
- * domain name, then the resolve library is broken.
- *
- * Warning: It is possible to fool this program into thinking everything is
- * alright by a clever use of /etc/hosts - but this is better than nothing.
- *
- * Usage:
- * resolve [hostname]
- *
- * When invoked with no arguments, gethostname is used for the local host.
- *
- */
-
-/* This program tests the resolve library and sees if it is broken... */
-
-#include "k5-platform.h"
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-int
-main(int argc, char **argv)
-{
- struct addrinfo *ai = NULL, hint;
- char myname[MAXHOSTNAMELEN + 1], namebuf[NI_MAXHOST], abuf[256];
- const char *addrstr;
- int err, quiet = 0;
-
- argc--; argv++;
- while (argc) {
- if ((strcmp(*argv, "--quiet") == 0) ||
- (strcmp(*argv, "-q") == 0)) {
- quiet++;
- } else
- break;
- argc--; argv++;
- }
-
- if (argc >= 1) {
- strlcpy(myname, *argv, sizeof(myname));
- } else {
- if(gethostname(myname, MAXHOSTNAMELEN)) {
- perror("gethostname failure");
- exit(1);
- }
- }
-
- myname[MAXHOSTNAMELEN] = '\0'; /* for safety */
-
- /* Look up the address... */
- if (!quiet)
- printf("Hostname: %s\n", myname);
-
- memset(&hint, 0, sizeof(hint));
- hint.ai_flags = AI_CANONNAME;
- err = getaddrinfo(myname, 0, &hint, &ai);
- if (err) {
- fprintf(stderr,
- "Could not look up address for hostname '%s' - fatal\n",
- myname);
- exit(2);
- }
-
- if (!quiet) {
- addrstr = inet_ntop(ai->ai_family, ai->ai_addr, abuf, sizeof(abuf));
- if (addrstr != NULL)
- printf("Host address: %s\n", addrstr);
- }
-
- err = getnameinfo(ai->ai_addr, ai->ai_addrlen, namebuf, sizeof(namebuf),
- NULL, 0, NI_NAMEREQD);
- if (err && !quiet)
- fprintf(stderr, "Error looking up IP address\n");
-
- printf("%s%s\n", quiet ? "" : "FQDN: ", err ? ai->ai_canonname : namebuf);
-
- if (!quiet)
- printf("Resolve library appears to have passed the test\n");
-
- freeaddrinfo(ai);
- return 0;
-}

View file

@ -1,861 +0,0 @@
From 404cc1152880a567fc27bb7c691a1a732692bbf9 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sat, 15 Feb 2020 20:34:23 -0500
Subject: [PATCH] Replace gssrpc tests with a Python script
Replace the dejagnu RPC test framework with a short Python script to
do the same tests as fullrun.exp and gsserr.exp. Modify the server
test program to facilitate use by k5test.py.
expire.exp, together with a comment in the client test program, was
designed to test a libdb2 btree bug via the gssrpc server-side
authentication code. That code was subsequently changed not to use
libdb2, before it was merged into the main krb5 tree (in revision 1.23
of svc_auth_gssapi.c, according to the changelog removed in commit
2a43d772be1e45faa8e488d436b6e867371563fb). Remove the comment and do
not replace that test sequence.
[rharwood@redhat.com: .gitignore]
---
src/configure.ac | 2 -
src/lib/rpc/unit-test/Makefile.in | 36 +--
src/lib/rpc/unit-test/client.c | 26 ---
src/lib/rpc/unit-test/config/unix.exp | 176 --------------
src/lib/rpc/unit-test/lib/helpers.exp | 234 -------------------
src/lib/rpc/unit-test/rpc_test.0/expire.exp | 49 ----
src/lib/rpc/unit-test/rpc_test.0/fullrun.exp | 91 --------
src/lib/rpc/unit-test/rpc_test.0/gsserr.exp | 30 ---
src/lib/rpc/unit-test/server.c | 13 +-
src/lib/rpc/unit-test/t_rpc.py | 29 +++
10 files changed, 41 insertions(+), 645 deletions(-)
delete mode 100644 src/lib/rpc/unit-test/config/unix.exp
delete mode 100644 src/lib/rpc/unit-test/lib/helpers.exp
delete mode 100644 src/lib/rpc/unit-test/rpc_test.0/expire.exp
delete mode 100644 src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
delete mode 100644 src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
create mode 100644 src/lib/rpc/unit-test/t_rpc.py
diff --git a/src/configure.ac b/src/configure.ac
index 29be532cb..aafc462f9 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1102,8 +1102,6 @@ extern void endrpcent();],
AC_MSG_RESULT($k5_cv_type_endrpcent)
AC_DEFINE_UNQUOTED(ENDRPCENT_TYPE, $k5_cv_type_endrpcent, [Define as return type of endrpcent])
K5_GEN_FILE(include/gssrpc/types.h:include/gssrpc/types.hin)
-PASS=tcp
-AC_SUBST(PASS)
# for pkinit
AC_ARG_ENABLE([pkinit],
diff --git a/src/lib/rpc/unit-test/Makefile.in b/src/lib/rpc/unit-test/Makefile.in
index 0b6e5203d..309ae2b21 100644
--- a/src/lib/rpc/unit-test/Makefile.in
+++ b/src/lib/rpc/unit-test/Makefile.in
@@ -16,10 +16,6 @@ server: server.o rpc_test_svc.o $(GSSRPC_DEPLIBS) $(KRB5_BASE_DEPLIBS)
client.o server.o: rpc_test.h
-runenv.exp: Makefile
- $(RUN_SETUP); for i in $(RUN_VARS); do \
- eval echo "set env\($$i\) \$$$$i"; done > runenv.exp
-
# If rpc_test.h and rpc_test_*.c do not work on your system, you can
# try using rpcgen by uncommenting these lines (be sure to uncomment
# then in the generated not Makefile.in).
@@ -34,37 +30,9 @@ runenv.exp: Makefile
# rm -f rpc_test.h rpc_test_clnt.c rpc_test_svc.c
#
-check unit-test: unit-test-@DO_TEST@
-
-unit-test-:
- @echo "+++"
- @echo "+++ WARNING: lib/rpc unit tests not run."
- @echo "+++ Either tcl, runtest, or Perl is unavailable."
- @echo "+++"
- @echo 'Skipped rpc tests: runtest or Perl not found' >> $(SKIPTESTS)
-
-unit-test-ok: unit-test-body
-
-PASS=@PASS@
-unit-test-body: runenv.sh runenv.exp
- $(RM) krb5cc_rpc_test_*
- $(ENV_SETUP) $(VALGRIND) $(START_SERVERS)
- RPC_TEST_KEYTAB=/tmp/rpc_test_keytab.$$$$ ; export RPC_TEST_KEYTAB ; \
- trap "echo Failed, cleaning up... ; rm -f $$RPC_TEST_KEYTAB ; $(ENV_SETUP) $(STOP_SERVERS) ; trap '' 0 ; exit 1" 0 1 2 3 14 15 ; \
- if $(ENV_SETUP) \
- $(RUNTEST) SERVER=./server CLIENT=./client \
- KINIT=$(BUILDTOP)/clients/kinit/kinit \
- KDESTROY=$(BUILDTOP)/clients/kdestroy/kdestroy \
- PRIOCNTL_HACK=@PRIOCNTL_HACK@ VALGRIND="$(VALGRIND)" \
- PASS="$(PASS)" --tool rpc_test $(RUNTESTFLAGS) ; \
- then \
- echo Cleaning up... ; \
- rm -f $$RPC_TEST_KEYTAB krb5cc_rpc_test_* ; \
- $(ENV_SETUP) $(STOP_SERVERS) ; \
- trap 0 ; exit 0 ; \
- else exit 1 ; fi
+check-pytests:
+ $(RUNPYTEST) $(srcdir)/t_rpc.py $(PYTESTFLAGS)
clean:
$(RM) server client
- $(RM) dbg.log rpc_test.log rpc_test.sum runenv.exp
diff --git a/src/lib/rpc/unit-test/client.c b/src/lib/rpc/unit-test/client.c
index 5edde49df..c9a812bc5 100644
--- a/src/lib/rpc/unit-test/client.c
+++ b/src/lib/rpc/unit-test/client.c
@@ -231,32 +231,6 @@ main(argc, argv)
else
gssrpc_xdr_free(xdr_wrapstring, echo_resp);
- /*
- * Test fix for secure-rpc/586, part 1: btree keys must be
- * unique. Create another context from the same credentials; it
- * should have the same expiration time and will cause the server
- * to abort if the clients are not differentiated.
- *
- * Test fix for secure-rpc/586, part 2: btree keys cannot be
- * mutated in place. To test this: a second client, *with a
- * later expiration time*, must be run. The second client should
- * destroy itself *after* the first one; if the key-mutating bug
- * is not fixed, the second client_data will be in the btree
- * before the first, but its key will be larger; thus, when the
- * first client calls AUTH_DESTROY, the server won't find it in
- * the btree and call abort.
- *
- * For unknown reasons, running just a second client didn't
- * tickle the bug; the btree code seemed to guess which node to
- * look at first. Running a total of three clients does ticket
- * the bug. Thus, the full test sequence looks like this:
- *
- * kinit -l 20m user && client server test@ddn 200
- * sleep 1
- * kini -l 30m user && client server test@ddn 300
- * sleep 1
- * kinit -l 40m user && client server test@ddn 400
- */
if (! auth_once) {
tmp_auth = clnt->cl_auth;
clnt->cl_auth = auth_gssapi_create_default(clnt, target);
diff --git a/src/lib/rpc/unit-test/config/unix.exp b/src/lib/rpc/unit-test/config/unix.exp
deleted file mode 100644
index 18da62be4..000000000
--- a/src/lib/rpc/unit-test/config/unix.exp
+++ /dev/null
@@ -1,176 +0,0 @@
-#
-# $Id$
-#
-
-source runenv.exp
-
-set kill /bin/kill
-set sleep /bin/sleep
-set kinit $KINIT
-set kdestroy $KDESTROY
-
-set hostname [exec hostname]
-
-# Hack around Solaris 9 kernel race condition that causes last output
-# from a pty to get dropped.
-if { $PRIOCNTL_HACK } {
- catch {exec priocntl -s -c FX -m 30 -p 30 -i pid [getpid]}
- rename spawn oldspawn
- proc spawn { args } {
- upvar 1 spawn_id spawn_id
- set newargs {}
- set inflags 1
- set eatnext 0
- foreach arg $args {
- if { $arg == "-ignore" \
- || $arg == "-open" \
- || $arg == "-leaveopen" } {
- lappend newargs $arg
- set eatnext 1
- continue
- }
- if [string match "-*" $arg] {
- lappend newargs $arg
- continue
- }
- if { $eatnext } {
- set eatnext 0
- lappend newargs $arg
- continue
- }
- if { $inflags } {
- set inflags 0
- set newargs [concat $newargs {priocntl -e -c FX -p 0}]
- }
- lappend newargs $arg
- }
- set pid [eval oldspawn $newargs]
- return $pid
- }
-}
-
-if { [string length $VALGRIND] } {
- rename spawn valgrind_aux_spawn
- proc spawn { args } {
- global VALGRIND
- upvar 1 spawn_id spawn_id
- set newargs {}
- set inflags 1
- set eatnext 0
- foreach arg $args {
- if { $arg == "-ignore" \
- || $arg == "-open" \
- || $arg == "-leaveopen" } {
- lappend newargs $arg
- set eatnext 1
- continue
- }
- if [string match "-*" $arg] {
- lappend newargs $arg
- continue
- }
- if { $eatnext } {
- set eatnext 0
- lappend newargs $arg
- continue
- }
- if { $inflags } {
- set inflags 0
- # Only run valgrind for local programs, not
- # system ones.
-#&&![string match "/bin/sh" $arg] sh is used to start kadmind!
- if [string match "/" [string index $arg 0]]&&![string match "/bin/ls" $arg]&&![regexp {/kshd$} $arg] {
- set newargs [concat $newargs $VALGRIND]
- } elseif [string match "." [string index $arg 0]] {
- set newargs [concat $newargs $VALGRIND]
- }
- }
- lappend newargs $arg
- }
- set pid [eval valgrind_aux_spawn $newargs]
- return $pid
- }
-}
-
-# this will initialize the database and keytab
-load_lib "helpers.exp"
-
-proc rpc_test_version {} {
- global CLIENT
- global SERVER
-
- clone_output "$CLIENT version <unknown>"
- clone_output "$SERVER version <unknown>"
-}
-
-proc rpc_test_load {} {
- #
-}
-
-# rpc_test_exit -- clean up and exit
-proc rpc_test_exit {} {
- global server_id
- global server_pid
- global server_started
- global kill
-
- if {[catch {
- expect {
- -i $server_id
- eof {
- fail "server exited!"
- verbose $expect_out(buffer) 1
- }
- timeout { pass "server survived" }
- }
- } tmp]} {
- fail "server exited! (expect failed)"
- }
-}
-
-#
-# rpc_test_start -- start the rpc_test server running
-#
-proc rpc_test_start { } {
- global SERVER PROT
- global server_id
- global server_pid
- global server_started
- global server_port
- global env
-
- if [info exists server_pid] { rpc_test_exit }
-
- set env(KRB5_KTNAME) FILE:$env(RPC_TEST_KEYTAB)
-
- verbose "% $SERVER" 1
- set server_pid [spawn $SERVER $PROT]
- set server_id $spawn_id
- set server_started 1
- set server_port -1
-
- unset env(KRB5_KTNAME)
-
- set timeout 30
-
- expect {
- -re "port: (\[0-9\]*)\r\n" {
- set server_port $expect_out(1,string)
- }
- "running" { }
- eof {
- send_error "server exited!"
- verbose $expect_out(buffer) 1
- }
- timeout {
- send_error "server didn't start in $timeout seconds"
- verbose $expect_out(buffer) 1
- }
- }
-
-}
-
-set MULTIPASS {
- {tcp PROT=-t dummy=[rpc_test_start]}
- {udp PROT=-u dummy=[rpc_test_start]}
-}
diff --git a/src/lib/rpc/unit-test/lib/helpers.exp b/src/lib/rpc/unit-test/lib/helpers.exp
deleted file mode 100644
index eb2797c53..000000000
--- a/src/lib/rpc/unit-test/lib/helpers.exp
+++ /dev/null
@@ -1,234 +0,0 @@
-if {[info commands exp_version] != {}} {
- set exp_version_4 [regexp {^4} [exp_version]]
-} else {
- set exp_version_4 [regexp {^4} [expect_version]]
-}
-
-# Backward compatibility until we're using expect 5 everywhere
-if {$exp_version_4} {
- global wait_error_index wait_errno_index wait_status_index
- set wait_error_index 0
- set wait_errno_index 1
- set wait_status_index 1
-} else {
- set wait_error_index 2
- set wait_errno_index 3
- set wait_status_index 3
-}
-
-proc set_from_env {varname default_value} {
- global env
- upvar $varname v
-
- if [info exists env($varname)] {
- set v $env($varname)
- } else {
- set v $default_value
- }
-}
-proc expect_tcl_prompt {} {
- global kadmin_tcl_spawn_id
- expect {
- -i $kadmin_tcl_spawn_id
- -re "^% $" { }
- -re . { perror "unexpected output {$expect_out(buffer)} from subprocess, expecting tcl prompt" }
- timeout { perror "timeout waiting for tcl prompt" }
- eof { perror "eof from subprocess when expecting tcl prompt" }
- }
-}
-proc send_tcl_cmd_await_echo {cmd} {
- global kadmin_tcl_spawn_id
- send -i $kadmin_tcl_spawn_id "$cmd\n"
- expect {
- -i $kadmin_tcl_spawn_id
- -ex "$cmd\r\n" { }
- timeout { perror "timeout waiting for tcl subprocess to echo input" }
- eof { perror "eof waiting for tcl subprocess to echo input" }
- }
-}
-proc expect_kadm_ok {} {
- global kadmin_tcl_spawn_id
- expect {
- -i $kadmin_tcl_spawn_id
- -re "^OK KADM5_OK \[^\n\]*\n" {}
- -re "^ERROR \[^\n\]*\n" { perror "kadmin tcl subprocess reported unexpected error" }
- -re "^marshall_new_creds: \[^\n\]*\n" { exp_continue }
- -re "^gssapi_\[^\n\]*\n" { exp_continue }
- -re "^\r?\n" { exp_continue }
- eof { perror "kadmin tcl subprocess died" }
- default { perror "didn't get ok back" }
- }
-}
-proc setup_database {} {
- global env spawn_id kadmin_tcl_spawn_id TESTDIR CANON_HOST
-
- # XXXXX
- set_from_env TOP {/x/x/x/x/x}
- send_user "TOP=$TOP\n"
-
- set_from_env TESTDIR $env(TOP)/testing
- set_from_env CLNTTCL $TESTDIR/util/kadm5_clnt_tcl
- set_from_env TCLUTIL $TESTDIR/tcl/util.t
- set env(TCLUTIL) $TCLUTIL
- set env(PATH) "$TOP/install/admin:$env(PATH)"
-
- # $VERBOSE ?
-
- if [info exists spawn_id] { set x $spawn_id }
- spawn $CLNTTCL
- set kadmin_tcl_spawn_id $spawn_id
- if [info exists x] { set spawn_id $x }
-
- expect_tcl_prompt
- # tcl 8.4 for some reason screws up autodetection of output EOL
- # translation. Work around it for now.
- send_tcl_cmd_await_echo "if { \[info commands fconfigure\] != \"\" } { fconfigure stdout -translation lf }"
- expect_tcl_prompt
- send_tcl_cmd_await_echo "source {$TCLUTIL}"
- expect_tcl_prompt
- send_tcl_cmd_await_echo "set h {$CANON_HOST}"
- expect {
- -ex "$CANON_HOST\r\n" { }
- timeout { perror "timeout waiting for subprocess" }
- eof { perror "eof from subprocess" }
- }
- expect_tcl_prompt
-
- send_tcl_cmd_await_echo {kadm5_init admin admin $KADM5_ADMIN_SERVICE null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 server_handle}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_create_principal $server_handle [simple_principal server/$h] {KADM5_PRINCIPAL} admin}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_randkey_principal $server_handle server/$h key null}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_create_principal $server_handle [simple_principal notserver/$h] {KADM5_PRINCIPAL} admin}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_randkey_principal $server_handle notserver/$h key null}
- expect_kadm_ok
- expect "^% "
- send_tcl_cmd_await_echo {kadm5_destroy $server_handle}
- expect_kadm_ok
- expect "^% "
- wait -nowait -i $spawn_id
- close -i $spawn_id
-}
-
-if ![info exists CANON_HOST] {
- set CANON_HOST $env(QUALNAME)
- setup_database
- file delete $env(RPC_TEST_KEYTAB)
- exec $env(TOP)/cli/kadmin -p admin -w admin ktadd -k $env(RPC_TEST_KEYTAB) server/$CANON_HOST
-}
-
-
-proc kinit {princ pass lifetime} {
- global kinit
- global wait_error_index wait_errno_index wait_status_index
-
- spawn -noecho $kinit -5 -l $lifetime $princ
- expect {
- -re "Password for $princ.*: " { send "$pass\n"; expect eof }
- timeout { perror "Timeout waiting for kinit"; close }
- eof
- }
-
- set ret [wait]
- if {[lindex $ret $wait_error_index] == -1} {
- perror \
- "wait(kinit $princ) returned error [lindex $ret $wait_errno_index]"
- } else {
- if {[lindex $ret $wait_status_index] != 0} {
- perror \
- "kinit $princ failed with [lindex $ret $wait_status_index]"
- }
- }
-}
-
-proc flush_server {} {
- global server_id
- global expect_out
-
- verbose "flushing server output" 1
-
- while {1} {
- set timeout 5
-
- expect {
- -i $server_id
- -re "^.+$" {
- verbose "server output: $expect_out(buffer)"
- }
- timeout { break }
- }
- }
-}
-
-proc start_client {testname ccname user password lifetime count
- {target ""}} {
- global env CLIENT PROT hostname server_port spawn_id verbose
-
- if {$target == ""} {
- set target "server@$hostname"
- }
-
- set env(KRB5CCNAME) FILE:[pwd]/krb5cc_rpc_test_$ccname
- kinit $user $password $lifetime
-
- if {$verbose > 0} {
- spawn $CLIENT -a 1 -s 1 -m 1 $PROT $hostname $server_port $target $count
- } else {
- spawn $CLIENT $PROT $hostname $server_port $target $count
- }
-
- verbose "$testname: client $ccname started"
-
- unset env(KRB5CCNAME)
-}
-
-proc eof_client {testname ccname id status} {
- verbose "$testname: eof'ing for client $ccname" 1
-
- expect {
- -i $id
- -re "^marshall_new_creds\[^\n\]*\n" { exp_continue }
- -re "^gssapi_\[^\n\]*\n" { exp_continue }
- -re "^\r?\n" { exp_continue }
- eof { verbose $expect_out(buffer) 1 }
- timeout {
- fail "$testname: timeout waiting for client $ccname to exit"
- }
- }
- wait_client $testname $ccname $id $status
-}
-
-
-proc wait_client {testname ccname id status} {
- global env
- global kill
- global kdestroy
- global wait_error_index wait_errno_index wait_status_index
-
- verbose "$testname: waiting for client $ccname" 1
-
- set ret [wait -i $id]
- if {[lindex $ret $wait_error_index] == -1} {
- fail \
- "$testname: wait $ccname returned error [lindex $ret $wait_errno_index]"
- } else {
- if {[lindex $ret $wait_status_index] == $status} {
- pass "$testname: client $ccname"
- } else {
- fail "$testname: client $ccname: unexpected return status [lindex $ret $wait_status_index], should be $status."
- }
- }
-
- set env(KRB5CCNAME) FILE:[pwd]/krb5cc_rpc_test_$ccname
- if {[catch "exec $kdestroy -5"] != 0} {
- perror "$testname: cannot destroy client $ccname ccache"
- }
-
- unset env(KRB5CCNAME)
-}
diff --git a/src/lib/rpc/unit-test/rpc_test.0/expire.exp b/src/lib/rpc/unit-test/rpc_test.0/expire.exp
deleted file mode 100644
index e19cca0ef..000000000
--- a/src/lib/rpc/unit-test/rpc_test.0/expire.exp
+++ /dev/null
@@ -1,49 +0,0 @@
-set timeout 40
-
-load_lib "helpers.exp"
-
-global server_started
-
-proc expired {} {
- global spawn_id server_id
-
- start_client expired expired testuser notathena -1m 100
- eof_client expired expired $spawn_id 2
-
- expect {
- -i $server_id
- -re "rpc_test server: Authen.*failed:.*credential.*expired" { pass "expired" }
- timeout { fail "expired: timeout waiting for expired creds error" }
- }
-
- flush_server
-}
-
-# This test doesn't work after #6948, because the client won't try to
-# authenticate using an expired TGT.
-#if { $server_started } {expired }
-
-proc overlap {} {
- global spawn_id
-
- start_client expire 1 testuser notathena 20m 100
- set client1_id $spawn_id
- flush_server
-
- start_client expire 2 testuser notathena 40m 300
- set client2_id $spawn_id
- flush_server
-
- start_client expire 3 testuser notathena 60m 500
- set client3_id $spawn_id
- flush_server
-
- eof_client expire 1 $client1_id 0
- eof_client expire 2 $client2_id 0
- eof_client expire 3 $client3_id 0
-
- flush_server
-}
-if { $server_started } {overlap}
-
-
diff --git a/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp b/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
deleted file mode 100644
index 73083de1f..000000000
--- a/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
+++ /dev/null
@@ -1,91 +0,0 @@
-set timeout 120
-
-load_lib "helpers.exp"
-
-global spawn_id
-global server_id
-global server_started
-
-if { !$server_started } {return}
-
-# Start the client and do a full run
-start_client "full run" fullrun testuser notathena 8h 1026
-set client_id $spawn_id
-
-#
-# test: did we get 11 dots?
-#
-verbose "Starting RPC echo test. This will take about 50 seconds.\n"
-
-set ver_line "rpc_test server: bad verifier\[^\r\n\]*\[\r\n]+"
-
-set dots 0
-set server_lines 0
-while {1} {
- expect {
- -i $server_id
- -re $ver_line {
- verbose "Got line from server."
- incr server_lines
- }
- default {
- exp_continue
- }
-
- -i $client_id
- . {
- incr dots
- verbose "$expect_out(buffer)" 1
- if ($dots==11) { break }
- }
- eof {
- #
- # test: was the exit status right?
- #
- wait_client "full run" fullrun $client_id 0
- break
- }
-
- timeout {
- verbose "Timeout waiting for dot\n" 1
- fail "full run: timeout waiting for dot"
- break
- }
- }
-}
-if {$dots==11} {
- pass "fullrun: echo test"
-} else {
- fail "fullrun: echo test: expected 11 dots, got $dots"
-}
-
-#
-# test: server logged four bad verifiers?
-#
-verbose "full run: checking server output"
-
-# Small timeout, since the server should have already printed everything
-set timeout 5
-
-while {$server_lines < 4} {
- expect {
- -i $server_id
- -re $ver_line {
- incr server_lines
- }
- -re ".+\r\n" {
- verbose "Unexpected server output: $expect_out(buffer)"
- }
- default {
- break
- }
- }
-}
-
-if {$server_lines == 4} {
- pass "fullrun: bad verifiers"
-} else {
- fail "fullrun: expected four bad verifiers, got $server_lines"
-}
-
-flush_server
diff --git a/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp b/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
deleted file mode 100644
index 005971989..000000000
--- a/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
+++ /dev/null
@@ -1,30 +0,0 @@
-set timeout 30
-
-load_lib "helpers.exp"
-
-global spawn_id
-global server_id
-global server_started
-global hostname
-
-if { !$server_started } {return}
-
-start_client "gss err" gsserr testuser notathena 8h 1026 notserver@$hostname
-
-eof_client "gss err" gsserr $spawn_id 2
-
-#
-# test: server logged an authentication attempted failed?
-#
-verbose "gss err: checking server output"
-
-expect {
- -i $server_id
- -re "rpc_test server: Authent.*failed: .* not found in keytab" {
- pass "gss err: server logged auth error"
- }
- eof { fail "gss err: server exited" }
- timeout { fail "gss err: timeout waiting for server output" }
-}
-
-flush_server
diff --git a/src/lib/rpc/unit-test/server.c b/src/lib/rpc/unit-test/server.c
index 13e99bb06..c3bbcbf8c 100644
--- a/src/lib/rpc/unit-test/server.c
+++ b/src/lib/rpc/unit-test/server.c
@@ -37,7 +37,7 @@ static void rpc_test_badverf(gss_name_t client, gss_name_t server,
caddr_t data);
#ifndef SERVICE_NAME
-#define SERVICE_NAME "server"
+#define SERVICE_NAME "host"
#endif
static void usage()
@@ -120,7 +120,6 @@ main(int argc, char **argv)
prot == IPPROTO_TCP ? "tcp" : "udp");
exit(1);
}
- printf("port: %d\n", (int)transp->xp_port);
if (svcauth_gssapi_set_names(names, 0) == FALSE) {
fprintf(stderr, "unable to set gssapi names\n");
@@ -144,6 +143,8 @@ main(int argc, char **argv)
signal(SIGTERM, handlesig);
#endif
printf("running\n");
+ printf("port: %d\n", (int)transp->xp_port);
+ fflush(stdout);
svc_run();
fprintf(stderr, "svc_run returned");
@@ -177,6 +178,7 @@ static void rpc_test_badverf(gss_name_t client, gss_name_t server,
inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr),
ntohs(rqst->rq_xprt->xp_raddr.sin_port),
(int) server_name.length, (char *) server_name.value);
+ fflush(stdout);
(void) gss_release_buffer(&minor_stat, &client_name);
(void) gss_release_buffer(&minor_stat, &server_name);
@@ -211,6 +213,7 @@ void rpc_test_badauth(OM_uint32 major, OM_uint32 minor,
printf("rpc_test server: Authentication attempt failed: %s", a);
log_badauth_display_status(major, minor);
printf("\n");
+ fflush(stdout);
}
void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg,
@@ -220,6 +223,7 @@ void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg,
a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
printf("Miscellaneous RPC error: %s, %s\n", a, error);
+ fflush(stdout);
}
void log_badauth_display_status(OM_uint32 major, OM_uint32 minor)
@@ -243,10 +247,12 @@ void log_badauth_display_status_1(OM_uint32 code, int type, int rec)
log_badauth_display_status_1(gssstat,GSS_C_GSS_CODE,1);
log_badauth_display_status_1(minor_stat,
GSS_C_MECH_CODE, 1);
- } else
+ } else {
printf("GSS-API authentication error %.*s: "
"recursive failure!\n", (int) msg.length,
(char *)msg.value);
+ }
+ fflush(stdout);
return;
}
@@ -256,4 +262,5 @@ void log_badauth_display_status_1(OM_uint32 code, int type, int rec)
if (!msg_ctx)
break;
}
+ fflush(stdout);
}
diff --git a/src/lib/rpc/unit-test/t_rpc.py b/src/lib/rpc/unit-test/t_rpc.py
new file mode 100644
index 000000000..4e565d25c
--- /dev/null
+++ b/src/lib/rpc/unit-test/t_rpc.py
@@ -0,0 +1,29 @@
+import re
+
+from k5test import *
+
+realm = K5Realm()
+
+server = realm.start_server(['./server', '-t'], 'running')
+line = server.stdout.readline()
+portstr = re.match(r'^port: (\d+)$', line).group(1)
+
+realm.run(['./client', '-t', hostname, portstr, 'host@' + hostname, '1026'],
+ expected_msg='...........')
+
+for i in range(4):
+ line = server.stdout.readline()
+ if 'rpc_test server: bad verifier from user@KRBTEST.COM at ' not in line:
+ fail('unexpected server message: ' + line)
+ output(line)
+
+realm.addprinc('nokey/' + hostname)
+
+realm.run(['./client', '-t', hostname, portstr, 'nokey@' + hostname, '1026'],
+ expected_code=2)
+
+line = server.stdout.readline()
+if 'rpc_test server: Authentication attempt failed: ' not in line:
+ fail('unexpected server message: ' + line)
+
+success('gssrpc auth_gssapi tests')

View file

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

View file

@ -1,41 +0,0 @@
From 3e0d464f55320b393e32285f31710c24758a9101 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Wed, 4 Mar 2020 17:18:51 -0500
Subject: [PATCH] Use two queues for concurrent t_otp.py daemons
t_otp.py occasionally fails during the #8708 regression test, reading
a true answer instead of the expected false answer during the first
verify() call. Most likely the daemons are writing their answers to
the shared queue out of order. Use a separate queue for the second
daemon to ensure correct correlation of results.
(cherry picked from commit c03f67eefec05db19e84e889fab7c25904929633)
---
src/tests/t_otp.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
index cba871a0f..c3b820a41 100755
--- a/src/tests/t_otp.py
+++ b/src/tests/t_otp.py
@@ -256,16 +256,17 @@ verify(daemon, queue, True, realm.user_princ, 'accept')
## tokens configured, with the first rejecting and the second
## accepting. With the bug, the KDC incorrectly rejects the request
## and then performs invalid memory accesses, most likely crashing.
+queue2 = Queue()
daemon1 = UDPRadiusDaemon(args=(server_addr, secret_file, 'accept1', queue))
-daemon2 = UnixRadiusDaemon(args=(socket_file, None, 'accept2', queue))
+daemon2 = UnixRadiusDaemon(args=(socket_file, None, 'accept2', queue2))
daemon1.start()
queue.get()
daemon2.start()
-queue.get()
+queue2.get()
oconf = '[' + otpconfig_1('udp') + ', ' + otpconfig_1('unix') + ']'
realm.run([kadminl, 'setstr', realm.user_princ, 'otp', oconf])
realm.kinit(realm.user_princ, 'accept2', flags=flags)
verify(daemon1, queue, False, realm.user_princ.split('@')[0], 'accept2')
-verify(daemon2, queue, True, realm.user_princ, 'accept2')
+verify(daemon2, queue2, True, realm.user_princ, 'accept2')
success('OTP tests')

1
ci.fmf Normal file
View file

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

View file

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

View file

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

View file

@ -1,24 +0,0 @@
From 4254bee1b97edeb0848efce635bcf1b56306f968 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 6796fec53..c4358988a 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -724,6 +724,7 @@ AC_HELP_STRING([--with-netlib=LIBS], use user defined resolver library),
LIBS="$LIBS $withval"
AC_MSG_RESULT("netlib will use \'$withval\'")
fi
+ KRB5_AC_ENABLE_DNS
],dnl
[AC_LIBRARY_NET]
)])dnl

8
gating.yaml Normal file
View file

@ -0,0 +1,8 @@
--- !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

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

View file

@ -1,3 +1,7 @@
[libdefaults]
# Allow RC4 HMAC-MD5 for session keys (see CVE-2022-37966)
#allow_rc4 = true
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88
@ -5,10 +9,12 @@
[realms]
EXAMPLE.COM = {
#master_key_type = aes256-cts
master_key_type = aes256-cts-hmac-sha384-192
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:normal aes128-cts:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal
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
}

View file

@ -1 +1 @@
d /var/run/krb5kdc 0755 root root
d /run/krb5kdc 0755 root root

18
krb5-tests Normal file
View file

@ -0,0 +1,18 @@
#!/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

1360
krb5.spec

File diff suppressed because it is too large Load diff

View file

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

5
plans/tests.fmf Normal file
View file

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

17
rpminspect.yaml Normal file
View file

@ -0,0 +1,17 @@
---
inspections:
# https://bugzilla.redhat.com/show_bug.cgi?id=1956479
badfuncs: off
# Not a Java package
javabytecode: off
# I need to be able to *add* functions, and also we export internal
# functions that are not considered part of our ABI.
abidiff: off
# These just flag when things change "too much"
changedfiles: off
filesize: off
patches: off
upstream: off

View file

@ -1,2 +1,2 @@
SHA512 (krb5-1.18.2.tar.gz) = 7cbb1b28e677fea3e0794e93951f3caaa2c49bb1175dd187951e72a466cc69d96c3b833d838000fe911c1a437d96a558e550f27c53a8b332fb9dfc7cbb7ec44c
SHA512 (krb5-1.18.2.tar.gz.asc) = 70775a06104b4d792d278da2efa92e94ddacb4ea319bfe2b253f5afcfec27f3bc5ddd12560294a265e3cf3d4fc74bcbfc3f5eeff8634d66c00d67e18dc93a74a
SHA512 (krb5-1.21.3.tar.gz) = 87bc06607f4d95ff604169cea22180703a42d667af05f66f1569b8bd592670c42820b335e5c279e8b4f066d1e7da20f1948a1e4def7c5d295c170cbfc7f49c71
SHA512 (krb5-1.21.3.tar.gz.asc) = 8992a5f5247315b9846aa73be4ee1ea223c0231a52d5c6c28718b1f3e3b45d62e2dad4aa5543a83163d1369bb79886b6c1c22766f22d8aa2f6b2575c54d0075c

View file

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

12
tests/got-audit/kdc.conf Normal file
View file

@ -0,0 +1,12 @@
[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
}

29
tests/got-audit/krb5.conf Normal file
View file

@ -0,0 +1,29 @@
# 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} = .

12
tests/got-audit/main.fmf Normal file
View file

@ -0,0 +1,12 @@
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

121
tests/got-audit/runtest.sh Executable file
View file

@ -0,0 +1,121 @@
#!/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

@ -55,6 +55,7 @@ $(METADATA): Makefile
@echo "TestTime: 20m" >> $(METADATA)
@echo "RunFor: krb5" >> $(METADATA)
@echo "Requires: expect krb5-server krb5-workstation openssh-clients openssh-server rng-tools" >> $(METADATA)
@echo "Requires: setools-console" >> $(METADATA)
@echo "Priority: Normal" >> $(METADATA)
@echo "License: GPLv2" >> $(METADATA)
@echo "Confidential: no" >> $(METADATA)

View file

@ -0,0 +1,21 @@
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

Some files were not shown because too many files have changed in this diff Show more