Compare commits

..

15 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
23 changed files with 6599 additions and 9 deletions

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,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

View file

@ -10,7 +10,7 @@
#
# baserelease is what we have standardized across Fedora and what
# rpmdev-bumpspec knows how to handle.
%global baserelease 2
%global baserelease 11
# This should be e.g. beta1 or %%nil
%global pre_release %nil
@ -84,6 +84,22 @@ Patch0022: 0022-Wait-indefinitely-on-KDC-TCP-connections.patch
Patch0023: 0023-Remove-PKINIT-RSA-support.patch
Patch0024: 0024-Fix-various-issues-detected-by-static-analysis.patch
Patch0025: 0025-Generate-and-verify-message-MACs-in-libkrad.patch
Patch0026: 0026-PKINIT-ECDH-support.patch
Patch0027: 0027-Add-ecdsa-with-sha512-256-to-supportedCMSTypes.patch
Patch0028: 0028-Get-rid-of-pkinit_crypto_openssl.h.patch
Patch0029: 0029-Use-SoftHSMv2-for-PKCS11-PKINIT-tests.patch
Patch0030: 0030-Simplify-PKINIT-cert-representation.patch
Patch0031: 0031-Support-PKCS11-EC-client-certs-in-PKINIT.patch
Patch0032: 0032-Improve-PKCS11-error-reporting-in-PKINIT.patch
Patch0033: 0033-Set-missing-mask-flags-for-kdb5_util-operations.patch
Patch0034: 0034-Prevent-overflow-when-calculating-ulog-block-size.patch
Patch0035: 0035-Don-t-issue-session-keys-with-deprecated-enctypes.patch
Patch0036: 0036-downstream-Remove-3des-support-cumulative-1.patch
Patch0037: 0037-Add-PKINIT-paChecksum2-from-MS-PKCA-v20230920.patch
Patch0038: 0038-downstream-Do-not-block-HMAC-MD4-5-in-FIPS-mode.patch
Patch0039: 0039-Fix-strchr-conformance-to-C23.patch
Patch0040: 0040-automated-fast.patch
Patch0041: 0041-bail-if-prompter-is-not-specified-but-required.patch
License: Brian-Gladman-2-Clause AND BSD-2-Clause AND (BSD-2-Clause OR GPL-2.0-or-later) AND BSD-2-Clause-first-lines AND BSD-3-Clause AND BSD-4-Clause AND CMU-Mach-nodoc AND FSFULLRWD AND HPND AND HPND-export2-US AND HPND-export-US AND HPND-export-US-acknowledgement AND HPND-export-US-modify AND ISC AND MIT AND MIT-CMU AND OLDAP-2.8 AND OpenVision
URL: https://web.mit.edu/kerberos/www/
@ -117,6 +133,8 @@ BuildRequires: openssl-devel < 1:3.0.0
# Enable compilation of optional tests
BuildRequires: resolv_wrapper
BuildRequires: libcmocka-devel
BuildRequires: opensc
BuildRequires: softhsm
%description
Kerberos V5 is a trusted-third-party network authentication system,
@ -148,7 +166,7 @@ Requires: openssl-libs >= 1:3.0.0
Requires: openssl-libs >= 1:1.1.1d-4
Requires: openssl-libs < 1:3.0.0
%endif
Requires: coreutils, gawk, sed
Requires: coreutils
Requires: keyutils-libs >= 1.5.8
Requires: /etc/crypto-policies/back-ends/krb5.config
@ -261,11 +279,16 @@ Requires: net-tools, rpcbind
Requires: perl-interpreter
Requires: procps-ng
Requires: python3-kdcproxy
Requires: python3-pyrad
Requires: resolv_wrapper
Requires: /etc/crypto-policies/back-ends/krb5.config
Requires: words
#Requires: openldap-servers, openldap-clients
Requires: opensc
Requires: softhsm
Recommends: python3-pyrad
# Restore once openldap upstream tests are fixed
#Recommends: openldap-servers
#Recommends: openldap-clients
%description tests
FOR TESTING PURPOSE ONLY
@ -511,14 +534,16 @@ install -pdm 755 $RPM_BUILD_ROOT%{_datarootdir}/%{name}-tests/%{_arch}
pushd src
cp -p --parents -t "$RPM_BUILD_ROOT%{_datarootdir}/%{name}-tests/%{_arch}/" \
$(find . -type f -exec file -i "{}" + \
| sed -ne 's|^\./\([^:]\+\): \+text/.\+$|\1|p' | grep -Ev '~$')
| sed -n \
-e 's|^\./\([^:]\+\): \+text/.\+$|\1|p' \
-e 's|^\./\([^:]\+\): \+application/x-pem-file.\+$|\1|p' \
-e 's|^\./\([^:]\+\): \+application/json.\+$|\1|p' \
| grep -Ev '~$')
popd
# Copy binary test files
install -pm 644 src/tests/pkinit-certs/*.p12 \
"$RPM_BUILD_ROOT%{_datarootdir}/%{name}-tests/%{_arch}/tests/pkinit-certs/"
install -pm 644 src/tests/au_dict.json \
"$RPM_BUILD_ROOT%{_datarootdir}/%{name}-tests/%{_arch}/tests/"
# Unset executable bit if no shebang in script
for f in $(find "$RPM_BUILD_ROOT%{_datarootdir}/%{name}-tests/%{_arch}/" -type f -executable)
@ -720,7 +745,48 @@ exit 0
%{_datarootdir}/%{name}-tests/%{_arch}
%changelog
* Wed Oct 30 2024 Julien Rische <jrische@redhat.com> - 1.21.3-2
* Mon Jan 05 2026 Julien Rische <jrische@redhat.com> - 1.21.3-11
- Fix strchr() conformance to C23
* Mon Oct 20 2025 Alexander Bokovoy <abokovoy@redhat.com> - 1.21.3-10
- Update the prompter patch to upstream version
Resolves: rhbz#2403513
* Wed Oct 15 2025 Alexander Bokovoy <abokovoy@redhat.com> - 1.21.3-9
- do not crash when prompter is not available in GSSAPI
Resolves: rhbz#2403513
* Fri Sep 26 2025 Alexander Bokovoy <abokovoy@redhat.com> - 1.21.3-8
- Add automated FAST channel for kinit
- https://github.com/krb5/krb5/pull/1447 - work in progress
* Thu Jul 24 2025 Fedora Release Engineering <releng@fedoraproject.org> - 1.21.3-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild
* Wed Jun 04 2025 Julien Rische <jrische@redhat.com> - 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
* Wed Jan 29 2025 Julien Rische <jrische@redhat.com> - 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
* Fri Jan 17 2025 Fedora Release Engineering <releng@fedoraproject.org> - 1.21.3-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild
* Wed Oct 30 2024 Julien Rische <jrische@redhat.com> - 1.21.3-3
- libkrad: implement support for Message-Authenticator (CVE-2024-3596)
Resolves: rhbz#2304071
- Fix various issues detected by static analysis
@ -730,6 +796,9 @@ exit 0
- Make TCP waiting time configurable
Resolves: rhbz#2322711
* Thu Jul 18 2024 Fedora Release Engineering <releng@fedoraproject.org> - 1.21.3-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild
* Tue Jul 09 2024 Julien Rische <jrische@redhat.com> - 1.21.3-1
- New upstream version (1.21.3)
- CVE-2024-26458: Memory leak in src/lib/rpc/pmap_rmt.c
@ -741,13 +810,19 @@ exit 0
- Add missing SPDX license identifiers
Resolves: rhbz#2265333
* Mon Jul 08 2024 Julien Rische <jrische@redhat.com> - 1.21.2-4
* Mon Jul 08 2024 Julien Rische <jrische@redhat.com> - 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
* Thu Jan 25 2024 Fedora Release Engineering <releng@fedoraproject.org> - 1.21.2-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Sun Jan 21 2024 Fedora Release Engineering <releng@fedoraproject.org> - 1.21.2-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Wed Jan 17 2024 Julien Rische <jrische@redhat.com> - 1.21.2-3
- Fix double free in klist's show_ccache()
Resolves: rhbz#2257301

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