import krb5-1.19.1-15.el9_0
This commit is contained in:
commit
b78f880dae
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
SOURCES/krb5-1.19.1.tar.gz
|
1
.krb5.metadata
Normal file
1
.krb5.metadata
Normal file
@ -0,0 +1 @@
|
||||
65fcedf85595457652cc0d37df65c9258e783d6b SOURCES/krb5-1.19.1.tar.gz
|
220
SOURCES/Add-APIs-for-marshalling-credentials.patch
Normal file
220
SOURCES/Add-APIs-for-marshalling-credentials.patch
Normal file
@ -0,0 +1,220 @@
|
||||
From 3d11179707923b033fa413387a33296b673ff52d Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Thu, 14 Jan 2021 18:13:09 -0500
|
||||
Subject: [PATCH] Add APIs for marshalling credentials
|
||||
|
||||
Faciliate KCM daemon implementations by providing functions to
|
||||
deserialize and reserialize credentials in the FILE v4 format.
|
||||
|
||||
[ghudson@mit.edu: minor editorial changes]
|
||||
|
||||
ticket: 8980 (new)
|
||||
(cherry picked from commit 18ea3bd2fca55b789b7de9c663624bc11d348fa6)
|
||||
---
|
||||
doc/appdev/refs/api/index.rst | 2 ++
|
||||
src/include/krb5/krb5.hin | 36 ++++++++++++++++++++++
|
||||
src/lib/krb5/ccache/ccmarshal.c | 53 +++++++++++++++++++++++++++++++++
|
||||
src/lib/krb5/ccache/t_marshal.c | 15 +++++++++-
|
||||
src/lib/krb5/libkrb5.exports | 2 ++
|
||||
src/lib/krb5_32.def | 4 +++
|
||||
6 files changed, 111 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst
|
||||
index 727d9b492..9e03fd386 100644
|
||||
--- a/doc/appdev/refs/api/index.rst
|
||||
+++ b/doc/appdev/refs/api/index.rst
|
||||
@@ -232,6 +232,7 @@ Rarely used public interfaces
|
||||
krb5_kt_remove_entry.rst
|
||||
krb5_kt_start_seq_get.rst
|
||||
krb5_make_authdata_kdc_issued.rst
|
||||
+ krb5_marshal_credentials.rst
|
||||
krb5_merge_authdata.rst
|
||||
krb5_mk_1cred.rst
|
||||
krb5_mk_error.rst
|
||||
@@ -285,6 +286,7 @@ Rarely used public interfaces
|
||||
krb5_tkt_creds_get_times.rst
|
||||
krb5_tkt_creds_init.rst
|
||||
krb5_tkt_creds_step.rst
|
||||
+ krb5_unmarshal_credentials.rst
|
||||
krb5_verify_init_creds.rst
|
||||
krb5_verify_init_creds_opt_init.rst
|
||||
krb5_verify_init_creds_opt_set_ap_req_nofail.rst
|
||||
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||
index 63e67a2ba..c26dde535 100644
|
||||
--- a/src/include/krb5/krb5.hin
|
||||
+++ b/src/include/krb5/krb5.hin
|
||||
@@ -3125,6 +3125,42 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
|
||||
krb5_ccache ccache, krb5_creds *in_creds,
|
||||
krb5_creds **out_creds);
|
||||
|
||||
+/**
|
||||
+ * Serialize a @c krb5_creds object.
|
||||
+ *
|
||||
+ * @param [in] context Library context
|
||||
+ * @param [in] creds The credentials object to serialize
|
||||
+ * @param [out] data_out The serialized credentials
|
||||
+ *
|
||||
+ * Serialize @a creds in the format used by the FILE ccache format (vesion 4)
|
||||
+ * and KCM ccache protocol.
|
||||
+ *
|
||||
+ * Use krb5_free_data() to free @a data_out when it is no longer needed.
|
||||
+ *
|
||||
+ * @retval 0 Success; otherwise - Kerberos error codes
|
||||
+ */
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_marshal_credentials(krb5_context context, krb5_creds *in_creds,
|
||||
+ krb5_data **data_out);
|
||||
+
|
||||
+/**
|
||||
+ * Deserialize a @c krb5_creds object.
|
||||
+ *
|
||||
+ * @param [in] context Library context
|
||||
+ * @param [in] data The serialized credentials
|
||||
+ * @param [out] creds_out The resulting creds object
|
||||
+ *
|
||||
+ * Deserialize @a data to credentials in the format used by the FILE ccache
|
||||
+ * format (vesion 4) and KCM ccache protocol.
|
||||
+ *
|
||||
+ * Use krb5_free_creds() to free @a creds_out when it is no longer needed.
|
||||
+ *
|
||||
+ * @retval 0 Success; otherwise - Kerberos error codes
|
||||
+ */
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_unmarshal_credentials(krb5_context context, const krb5_data *data,
|
||||
+ krb5_creds **creds_out);
|
||||
+
|
||||
/** @deprecated Replaced by krb5_get_validated_creds. */
|
||||
krb5_error_code KRB5_CALLCONV
|
||||
krb5_get_credentials_validate(krb5_context context, krb5_flags options,
|
||||
diff --git a/src/lib/krb5/ccache/ccmarshal.c b/src/lib/krb5/ccache/ccmarshal.c
|
||||
index ae634ccab..ab284e721 100644
|
||||
--- a/src/lib/krb5/ccache/ccmarshal.c
|
||||
+++ b/src/lib/krb5/ccache/ccmarshal.c
|
||||
@@ -515,3 +515,56 @@ k5_marshal_mcred(struct k5buf *buf, krb5_creds *mcred)
|
||||
if (mcred->second_ticket.length > 0)
|
||||
put_data(buf, version, &mcred->second_ticket);
|
||||
}
|
||||
+
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_marshal_credentials(krb5_context context, krb5_creds *in_creds,
|
||||
+ krb5_data **data_out)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_data *data;
|
||||
+ struct k5buf buf;
|
||||
+
|
||||
+ *data_out = NULL;
|
||||
+
|
||||
+ data = k5alloc(sizeof(krb5_data), &ret);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ k5_buf_init_dynamic(&buf);
|
||||
+ k5_marshal_cred(&buf, 4, in_creds);
|
||||
+
|
||||
+ ret = k5_buf_status(&buf);
|
||||
+ if (ret) {
|
||||
+ free(data);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* Steal payload from buf. */
|
||||
+ *data = make_data(buf.data, buf.len);
|
||||
+ *data_out = data;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_unmarshal_credentials(krb5_context context, const krb5_data *data,
|
||||
+ krb5_creds **creds_out)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_creds *creds;
|
||||
+
|
||||
+ *creds_out = NULL;
|
||||
+
|
||||
+ creds = k5alloc(sizeof(krb5_creds), &ret);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = k5_unmarshal_cred((unsigned char *)data->data, data->length, 4,
|
||||
+ creds);
|
||||
+ if (ret) {
|
||||
+ free(creds);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ *creds_out = creds;
|
||||
+ return 0;
|
||||
+}
|
||||
diff --git a/src/lib/krb5/ccache/t_marshal.c b/src/lib/krb5/ccache/t_marshal.c
|
||||
index bd0284afa..96e0931a2 100644
|
||||
--- a/src/lib/krb5/ccache/t_marshal.c
|
||||
+++ b/src/lib/krb5/ccache/t_marshal.c
|
||||
@@ -268,13 +268,14 @@ main(int argc, char **argv)
|
||||
krb5_context context;
|
||||
krb5_ccache cache;
|
||||
krb5_principal princ;
|
||||
- krb5_creds cred1, cred2;
|
||||
+ krb5_creds cred1, cred2, *alloc_cred;
|
||||
krb5_cc_cursor cursor;
|
||||
const char *filename;
|
||||
char *ccname, filebuf[256];
|
||||
int version, fd;
|
||||
const struct test *t;
|
||||
struct k5buf buf;
|
||||
+ krb5_data ser_data, *alloc_data;
|
||||
|
||||
if (argc != 2)
|
||||
abort();
|
||||
@@ -285,6 +286,18 @@ main(int argc, char **argv)
|
||||
if (krb5_init_context(&context) != 0)
|
||||
abort();
|
||||
|
||||
+ /* Test public functions for unmarshalling and marshalling. */
|
||||
+ ser_data = make_data((char *)tests[3].cred1, tests[3].cred1len);
|
||||
+ if (krb5_unmarshal_credentials(context, &ser_data, &alloc_cred) != 0)
|
||||
+ abort();
|
||||
+ verify_cred1(alloc_cred);
|
||||
+ if (krb5_marshal_credentials(context, alloc_cred, &alloc_data) != 0)
|
||||
+ abort();
|
||||
+ assert(alloc_data->length == tests[3].cred1len);
|
||||
+ assert(memcmp(tests[3].cred1, alloc_data->data, alloc_data->length) == 0);
|
||||
+ krb5_free_data(context, alloc_data);
|
||||
+ krb5_free_creds(context, alloc_cred);
|
||||
+
|
||||
for (version = FIRST_VERSION; version <= 4; version++) {
|
||||
t = &tests[version - 1];
|
||||
|
||||
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
|
||||
index 2d9d56530..adbfa332b 100644
|
||||
--- a/src/lib/krb5/libkrb5.exports
|
||||
+++ b/src/lib/krb5/libkrb5.exports
|
||||
@@ -489,6 +489,7 @@ krb5_lock_file
|
||||
krb5_make_authdata_kdc_issued
|
||||
krb5_make_full_ipaddr
|
||||
krb5_make_fulladdr
|
||||
+krb5_marshal_credentials
|
||||
krb5_mcc_ops
|
||||
krb5_merge_authdata
|
||||
krb5_mk_1cred
|
||||
@@ -592,6 +593,7 @@ krb5_timeofday
|
||||
krb5_timestamp_to_sfstring
|
||||
krb5_timestamp_to_string
|
||||
krb5_unlock_file
|
||||
+krb5_unmarshal_credentials
|
||||
krb5_unpack_full_ipaddr
|
||||
krb5_unparse_name
|
||||
krb5_unparse_name_ext
|
||||
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
|
||||
index 4953907aa..60b8dd311 100644
|
||||
--- a/src/lib/krb5_32.def
|
||||
+++ b/src/lib/krb5_32.def
|
||||
@@ -503,3 +503,7 @@ EXPORTS
|
||||
; new in 1.19
|
||||
k5_cc_store_primary_cred @470 ; PRIVATE
|
||||
k5_kt_have_match @471 ; PRIVATE GSSAPI
|
||||
+
|
||||
+; new in 1.20
|
||||
+ krb5_marshal_credentials @472
|
||||
+ krb5_unmarshal_credentials @473
|
359
SOURCES/Add-KCM_OP_GET_CRED_LIST-for-faster-iteration.patch
Normal file
359
SOURCES/Add-KCM_OP_GET_CRED_LIST-for-faster-iteration.patch
Normal file
@ -0,0 +1,359 @@
|
||||
From 418e64100d1e3f8c8e3f773909347bad270a2921 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
|
||||
Date: Thu, 11 Feb 2021 15:33:10 +0100
|
||||
Subject: [PATCH] Add KCM_OP_GET_CRED_LIST for faster iteration
|
||||
|
||||
For large caches, one IPC operation per credential dominates the cost
|
||||
of iteration. Instead transfer the whole list of credentials to the
|
||||
client in one IPC operation.
|
||||
|
||||
Add optional support for the new opcode to the test KCM server to
|
||||
allow testing of the main and fallback code paths.
|
||||
|
||||
[ghudson@mit.edu: fixed memory leaks and potential memory errors;
|
||||
adjusted code style and comments; rewrote commit message; added
|
||||
kcmserver.py support and tests]
|
||||
|
||||
ticket: 8990 (new)
|
||||
(cherry picked from commit 81bdb47d8ded390263d8ee48f71d5c312b4f1736)
|
||||
(cherry picked from commit a0ee8b02e56c65e5dcd569caed0e151cef004ef4)
|
||||
---
|
||||
src/include/kcm.h | 12 ++-
|
||||
src/lib/krb5/ccache/cc_kcm.c | 144 ++++++++++++++++++++++++++++++++---
|
||||
src/tests/kcmserver.py | 28 ++++++-
|
||||
src/tests/t_ccache.py | 10 ++-
|
||||
4 files changed, 175 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/src/include/kcm.h b/src/include/kcm.h
|
||||
index 5ea1447cd..e4140c3a0 100644
|
||||
--- a/src/include/kcm.h
|
||||
+++ b/src/include/kcm.h
|
||||
@@ -51,9 +51,9 @@
|
||||
*
|
||||
* All replies begin with a 32-bit big-endian reply code.
|
||||
*
|
||||
- * Parameters are appended to the request or reply with no delimiters. Flags
|
||||
- * and time offsets are stored as 32-bit big-endian integers. Names are
|
||||
- * marshalled as zero-terminated strings. Principals and credentials are
|
||||
+ * Parameters are appended to the request or reply with no delimiters. Flags,
|
||||
+ * time offsets, and lengths are stored as 32-bit big-endian integers. Names
|
||||
+ * are marshalled as zero-terminated strings. Principals and credentials are
|
||||
* marshalled in the v4 FILE ccache format. UUIDs are 16 bytes. UUID lists
|
||||
* are not delimited, so nothing can come after them.
|
||||
*/
|
||||
@@ -89,7 +89,11 @@ typedef enum kcm_opcode {
|
||||
KCM_OP_HAVE_NTLM_CRED,
|
||||
KCM_OP_DEL_NTLM_CRED,
|
||||
KCM_OP_DO_NTLM_AUTH,
|
||||
- KCM_OP_GET_NTLM_USER_LIST
|
||||
+ KCM_OP_GET_NTLM_USER_LIST,
|
||||
+
|
||||
+ /* MIT extensions */
|
||||
+ KCM_OP_MIT_EXTENSION_BASE = 13000,
|
||||
+ KCM_OP_GET_CRED_LIST, /* (name) -> (count, count*{len, cred}) */
|
||||
} kcm_opcode;
|
||||
|
||||
#endif /* KCM_H */
|
||||
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||
index 9093f894d..772928e4d 100644
|
||||
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||
@@ -61,6 +61,17 @@ struct uuid_list {
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
+struct cred_list {
|
||||
+ krb5_creds *creds;
|
||||
+ size_t count;
|
||||
+ size_t pos;
|
||||
+};
|
||||
+
|
||||
+struct kcm_cursor {
|
||||
+ struct uuid_list *uuids;
|
||||
+ struct cred_list *creds;
|
||||
+};
|
||||
+
|
||||
struct kcmio {
|
||||
SOCKET fd;
|
||||
#ifdef __APPLE__
|
||||
@@ -489,6 +500,69 @@ free_uuid_list(struct uuid_list *uuids)
|
||||
free(uuids);
|
||||
}
|
||||
|
||||
+static void
|
||||
+free_cred_list(struct cred_list *list)
|
||||
+{
|
||||
+ size_t i;
|
||||
+
|
||||
+ if (list == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ /* Creds are transferred to the caller as list->pos is incremented, so we
|
||||
+ * can start freeing there. */
|
||||
+ for (i = list->pos; i < list->count; i++)
|
||||
+ krb5_free_cred_contents(NULL, &list->creds[i]);
|
||||
+ free(list->creds);
|
||||
+ free(list);
|
||||
+}
|
||||
+
|
||||
+/* Fetch a cred list from req->reply. */
|
||||
+static krb5_error_code
|
||||
+kcmreq_get_cred_list(struct kcmreq *req, struct cred_list **creds_out)
|
||||
+{
|
||||
+ struct cred_list *list;
|
||||
+ const unsigned char *data;
|
||||
+ krb5_error_code ret = 0;
|
||||
+ size_t count, len, i;
|
||||
+
|
||||
+ *creds_out = NULL;
|
||||
+
|
||||
+ /* Check a rough bound on the count to prevent very large allocations. */
|
||||
+ count = k5_input_get_uint32_be(&req->reply);
|
||||
+ if (count > req->reply.len / 4)
|
||||
+ return KRB5_KCM_MALFORMED_REPLY;
|
||||
+
|
||||
+ list = malloc(sizeof(*list));
|
||||
+ if (list == NULL)
|
||||
+ return ENOMEM;
|
||||
+
|
||||
+ list->creds = NULL;
|
||||
+ list->count = count;
|
||||
+ list->pos = 0;
|
||||
+ list->creds = k5calloc(count, sizeof(*list->creds), &ret);
|
||||
+ if (list->creds == NULL) {
|
||||
+ free(list);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < count; i++) {
|
||||
+ len = k5_input_get_uint32_be(&req->reply);
|
||||
+ data = k5_input_get_bytes(&req->reply, len);
|
||||
+ if (data == NULL)
|
||||
+ break;
|
||||
+ ret = k5_unmarshal_cred(data, len, 4, &list->creds[i]);
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+ }
|
||||
+ if (i < count) {
|
||||
+ free_cred_list(list);
|
||||
+ return (ret == ENOMEM) ? ENOMEM : KRB5_KCM_MALFORMED_REPLY;
|
||||
+ }
|
||||
+
|
||||
+ *creds_out = list;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
kcmreq_free(struct kcmreq *req)
|
||||
{
|
||||
@@ -753,33 +827,53 @@ kcm_start_seq_get(krb5_context context, krb5_ccache cache,
|
||||
{
|
||||
krb5_error_code ret;
|
||||
struct kcmreq req = EMPTY_KCMREQ;
|
||||
- struct uuid_list *uuids;
|
||||
+ struct uuid_list *uuids = NULL;
|
||||
+ struct cred_list *creds = NULL;
|
||||
+ struct kcm_cursor *cursor;
|
||||
|
||||
*cursor_out = NULL;
|
||||
|
||||
get_kdc_offset(context, cache);
|
||||
|
||||
- kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
|
||||
+ kcmreq_init(&req, KCM_OP_GET_CRED_LIST, cache);
|
||||
ret = cache_call(context, cache, &req);
|
||||
- if (ret)
|
||||
+ if (ret == 0) {
|
||||
+ /* GET_CRED_LIST is available. */
|
||||
+ ret = kcmreq_get_cred_list(&req, &creds);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ } else if (ret == KRB5_FCC_INTERNAL) {
|
||||
+ /* Fall back to GET_CRED_UUID_LIST. */
|
||||
+ kcmreq_free(&req);
|
||||
+ kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
|
||||
+ ret = cache_call(context, cache, &req);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ ret = kcmreq_get_uuid_list(&req, &uuids);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ } else {
|
||||
goto cleanup;
|
||||
- ret = kcmreq_get_uuid_list(&req, &uuids);
|
||||
- if (ret)
|
||||
+ }
|
||||
+
|
||||
+ cursor = k5alloc(sizeof(*cursor), &ret);
|
||||
+ if (cursor == NULL)
|
||||
goto cleanup;
|
||||
- *cursor_out = (krb5_cc_cursor)uuids;
|
||||
+ cursor->uuids = uuids;
|
||||
+ cursor->creds = creds;
|
||||
+ *cursor_out = (krb5_cc_cursor)cursor;
|
||||
|
||||
cleanup:
|
||||
kcmreq_free(&req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static krb5_error_code KRB5_CALLCONV
|
||||
-kcm_next_cred(krb5_context context, krb5_ccache cache, krb5_cc_cursor *cursor,
|
||||
- krb5_creds *cred_out)
|
||||
+static krb5_error_code
|
||||
+next_cred_by_uuid(krb5_context context, krb5_ccache cache,
|
||||
+ struct uuid_list *uuids, krb5_creds *cred_out)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
struct kcmreq req;
|
||||
- struct uuid_list *uuids = (struct uuid_list *)*cursor;
|
||||
|
||||
memset(cred_out, 0, sizeof(*cred_out));
|
||||
|
||||
@@ -797,11 +891,39 @@ kcm_next_cred(krb5_context context, krb5_ccache cache, krb5_cc_cursor *cursor,
|
||||
return map_invalid(ret);
|
||||
}
|
||||
|
||||
+static krb5_error_code KRB5_CALLCONV
|
||||
+kcm_next_cred(krb5_context context, krb5_ccache cache, krb5_cc_cursor *cursor,
|
||||
+ krb5_creds *cred_out)
|
||||
+{
|
||||
+ struct kcm_cursor *c = (struct kcm_cursor *)*cursor;
|
||||
+ struct cred_list *list;
|
||||
+
|
||||
+ if (c->uuids != NULL)
|
||||
+ return next_cred_by_uuid(context, cache, c->uuids, cred_out);
|
||||
+
|
||||
+ list = c->creds;
|
||||
+ if (list->pos >= list->count)
|
||||
+ return KRB5_CC_END;
|
||||
+
|
||||
+ /* Transfer memory ownership of one cred to the caller. */
|
||||
+ *cred_out = list->creds[list->pos];
|
||||
+ memset(&list->creds[list->pos], 0, sizeof(*list->creds));
|
||||
+ list->pos++;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
kcm_end_seq_get(krb5_context context, krb5_ccache cache,
|
||||
krb5_cc_cursor *cursor)
|
||||
{
|
||||
- free_uuid_list((struct uuid_list *)*cursor);
|
||||
+ struct kcm_cursor *c = *cursor;
|
||||
+
|
||||
+ if (c == NULL)
|
||||
+ return 0;
|
||||
+ free_uuid_list(c->uuids);
|
||||
+ free_cred_list(c->creds);
|
||||
+ free(c);
|
||||
*cursor = NULL;
|
||||
return 0;
|
||||
}
|
||||
diff --git a/src/tests/kcmserver.py b/src/tests/kcmserver.py
|
||||
index 57432e5a7..8c5e66ff1 100644
|
||||
--- a/src/tests/kcmserver.py
|
||||
+++ b/src/tests/kcmserver.py
|
||||
@@ -23,6 +23,7 @@
|
||||
# traceback.print_exception(etype, value, tb, file=f)
|
||||
# sys.excepthook = ehook
|
||||
|
||||
+import optparse
|
||||
import select
|
||||
import socket
|
||||
import struct
|
||||
@@ -49,12 +50,14 @@ class KCMOpcodes(object):
|
||||
SET_DEFAULT_CACHE = 21
|
||||
GET_KDC_OFFSET = 22
|
||||
SET_KDC_OFFSET = 23
|
||||
+ GET_CRED_LIST = 13001
|
||||
|
||||
|
||||
class KRB5Errors(object):
|
||||
KRB5_CC_END = -1765328242
|
||||
KRB5_CC_NOSUPP = -1765328137
|
||||
KRB5_FCC_NOFILE = -1765328189
|
||||
+ KRB5_FCC_INTERNAL = -1765328188
|
||||
|
||||
|
||||
def make_uuid():
|
||||
@@ -183,6 +186,14 @@ def op_set_kdc_offset(argbytes):
|
||||
return 0, b''
|
||||
|
||||
|
||||
+def op_get_cred_list(argbytes):
|
||||
+ name, rest = unmarshal_name(argbytes)
|
||||
+ cache = get_cache(name)
|
||||
+ creds = [cache.creds[u] for u in cache.cred_uuids]
|
||||
+ return 0, (struct.pack('>L', len(creds)) +
|
||||
+ b''.join(struct.pack('>L', len(c)) + c for c in creds))
|
||||
+
|
||||
+
|
||||
ophandlers = {
|
||||
KCMOpcodes.GEN_NEW : op_gen_new,
|
||||
KCMOpcodes.INITIALIZE : op_initialize,
|
||||
@@ -197,7 +208,8 @@ ophandlers = {
|
||||
KCMOpcodes.GET_DEFAULT_CACHE : op_get_default_cache,
|
||||
KCMOpcodes.SET_DEFAULT_CACHE : op_set_default_cache,
|
||||
KCMOpcodes.GET_KDC_OFFSET : op_get_kdc_offset,
|
||||
- KCMOpcodes.SET_KDC_OFFSET : op_set_kdc_offset
|
||||
+ KCMOpcodes.SET_KDC_OFFSET : op_set_kdc_offset,
|
||||
+ KCMOpcodes.GET_CRED_LIST : op_get_cred_list
|
||||
}
|
||||
|
||||
# Read and respond to a request from the socket s.
|
||||
@@ -215,7 +227,11 @@ def service_request(s):
|
||||
|
||||
majver, minver, op = struct.unpack('>BBH', req[:4])
|
||||
argbytes = req[4:]
|
||||
- code, payload = ophandlers[op](argbytes)
|
||||
+
|
||||
+ if op in ophandlers:
|
||||
+ code, payload = ophandlers[op](argbytes)
|
||||
+ else:
|
||||
+ code, payload = KRB5Errors.KRB5_FCC_INTERNAL, b''
|
||||
|
||||
# The KCM response is the code (4 bytes) and the response payload.
|
||||
# The Heimdal IPC response is the length of the KCM response (4
|
||||
@@ -226,9 +242,15 @@ def service_request(s):
|
||||
s.sendall(hipc_response)
|
||||
return True
|
||||
|
||||
+parser = optparse.OptionParser()
|
||||
+parser.add_option('-c', '--credlist', action='store_true', dest='credlist',
|
||||
+ default=False, help='Support KCM_OP_GET_CRED_LIST')
|
||||
+(options, args) = parser.parse_args()
|
||||
+if not options.credlist:
|
||||
+ del ophandlers[KCMOpcodes.GET_CRED_LIST]
|
||||
|
||||
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
-server.bind(sys.argv[1])
|
||||
+server.bind(args[0])
|
||||
server.listen(5)
|
||||
select_input = [server,]
|
||||
sys.stderr.write('starting...\n')
|
||||
diff --git a/src/tests/t_ccache.py b/src/tests/t_ccache.py
|
||||
index 66804afa5..90040fb7b 100755
|
||||
--- a/src/tests/t_ccache.py
|
||||
+++ b/src/tests/t_ccache.py
|
||||
@@ -125,10 +125,18 @@ def collection_test(realm, ccname):
|
||||
|
||||
|
||||
collection_test(realm, 'DIR:' + os.path.join(realm.testdir, 'cc'))
|
||||
+
|
||||
+# Test KCM without and with GET_CRED_LIST support.
|
||||
kcmserver_path = os.path.join(srctop, 'tests', 'kcmserver.py')
|
||||
-realm.start_server([sys.executable, kcmserver_path, kcm_socket_path],
|
||||
+kcmd = realm.start_server([sys.executable, kcmserver_path, kcm_socket_path],
|
||||
+ 'starting...')
|
||||
+collection_test(realm, 'KCM:')
|
||||
+stop_daemon(kcmd)
|
||||
+os.remove(kcm_socket_path)
|
||||
+realm.start_server([sys.executable, kcmserver_path, '-c', kcm_socket_path],
|
||||
'starting...')
|
||||
collection_test(realm, 'KCM:')
|
||||
+
|
||||
if test_keyring:
|
||||
def cleanup_keyring(anchor, name):
|
||||
out = realm.run(['keyctl', 'list', anchor])
|
@ -0,0 +1,25 @@
|
||||
From 2f039fc910022c9569fe6941a194f0b26bd6c894 Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Fri, 20 Sep 2019 16:11:29 -0400
|
||||
Subject: [PATCH] Add buildsystem detection of the OpenSSL-3 KDF interface
|
||||
|
||||
(cherry picked from commit a3e03dfd40928c4615bd9b8546eac0c104377850)
|
||||
---
|
||||
src/configure.ac | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/src/configure.ac b/src/configure.ac
|
||||
index eb6307468..9c2e816fe 100644
|
||||
--- a/src/configure.ac
|
||||
+++ b/src/configure.ac
|
||||
@@ -282,6 +282,10 @@ AC_SUBST(CRYPTO_IMPL)
|
||||
AC_SUBST(CRYPTO_IMPL_CFLAGS)
|
||||
AC_SUBST(CRYPTO_IMPL_LIBS)
|
||||
|
||||
+if test "$CRYPTO_IMPL" = openssl; then
|
||||
+ AC_CHECK_FUNCS(EVP_KDF_fetch)
|
||||
+fi
|
||||
+
|
||||
AC_ARG_WITH([prng-alg],
|
||||
AC_HELP_STRING([--with-prng-alg=ALG], [use specified PRNG algorithm. @<:@fortuna@:>@]),
|
||||
[PRNG_ALG=$withval
|
@ -0,0 +1,84 @@
|
||||
From c76a01279bbbbcfd296d2ead8f6e2a5bee7e8443 Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Fri, 15 Jan 2021 14:43:34 -0500
|
||||
Subject: [PATCH] Add hostname canonicalization helper to k5test.py
|
||||
|
||||
To facilitate fallback tests, add a canonicalize_hostname() function
|
||||
to k5test.py which works similarly to krb5_expand_hostname(). Use it
|
||||
in t_gssapi.py for the recently-added acceptor name fallback test.
|
||||
|
||||
(cherry picked from commit 225fffe4e912772acea3a01d45bafb60bfb80948)
|
||||
---
|
||||
src/tests/gssapi/t_gssapi.py | 11 +++--------
|
||||
src/util/k5test.py | 22 ++++++++++++++++++++++
|
||||
2 files changed, 25 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
|
||||
index 1af6f31c2..e22cec427 100755
|
||||
--- a/src/tests/gssapi/t_gssapi.py
|
||||
+++ b/src/tests/gssapi/t_gssapi.py
|
||||
@@ -8,7 +8,7 @@ for realm in multipass_realms():
|
||||
realm.run(['./t_iov', '-s', 'p:' + realm.host_princ])
|
||||
realm.run(['./t_pcontok', 'p:' + realm.host_princ])
|
||||
|
||||
-realm = K5Realm(krb5_conf={'libdefaults': {'rdns': 'false'}})
|
||||
+realm = K5Realm()
|
||||
|
||||
# Test gss_add_cred().
|
||||
realm.run(['./t_add_cred'])
|
||||
@@ -62,13 +62,8 @@ realm.run(['./t_accname', 'p:host/-nomatch-',
|
||||
expected_msg=' not found in keytab')
|
||||
|
||||
# If possible, test with an acceptor name requiring fallback to match
|
||||
-# against a keytab entry. Forward-canonicalize the hostname, relying
|
||||
-# on the rdns=false realm setting.
|
||||
-try:
|
||||
- ai = socket.getaddrinfo(hostname, None, 0, 0, 0, socket.AI_CANONNAME)
|
||||
- (family, socktype, proto, canonname, sockaddr) = ai[0]
|
||||
-except socket.gaierror:
|
||||
- canonname = hostname
|
||||
+# against a keytab entry.
|
||||
+canonname = canonicalize_hostname(hostname)
|
||||
if canonname != hostname:
|
||||
os.rename(realm.keytab, realm.keytab + '.save')
|
||||
canonprinc = 'host/' + canonname
|
||||
diff --git a/src/util/k5test.py b/src/util/k5test.py
|
||||
index 789b0f4b9..251d11a9d 100644
|
||||
--- a/src/util/k5test.py
|
||||
+++ b/src/util/k5test.py
|
||||
@@ -155,6 +155,10 @@ Scripts may use the following functions and variables:
|
||||
* password(name): Return a weakly random password based on name. The
|
||||
password will be consistent across calls with the same name.
|
||||
|
||||
+* canonicalize_hostname(name, rdns=True): Return the DNS
|
||||
+ canonicalization of name, optionally using reverse DNS. On error,
|
||||
+ return name converted to lowercase.
|
||||
+
|
||||
* stop_daemon(proc): Stop a daemon process started with
|
||||
realm.start_server() or realm.start_in_inetd(). Only necessary if
|
||||
the port needs to be reused; daemon processes will be stopped
|
||||
@@ -458,6 +462,24 @@ def password(name):
|
||||
return name + str(os.getpid())
|
||||
|
||||
|
||||
+def canonicalize_hostname(name, rdns=True):
|
||||
+ """Canonicalize name using DNS, optionally with reverse DNS."""
|
||||
+ try:
|
||||
+ ai = socket.getaddrinfo(name, None, 0, 0, 0, socket.AI_CANONNAME)
|
||||
+ except socket.gaierror as e:
|
||||
+ return name.lower()
|
||||
+ (family, socktype, proto, canonname, sockaddr) = ai[0]
|
||||
+
|
||||
+ if not rdns:
|
||||
+ return canonname.lower()
|
||||
+
|
||||
+ try:
|
||||
+ rname = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
|
||||
+ except socket.gaierror:
|
||||
+ return canonname.lower()
|
||||
+ return rname[0].lower()
|
||||
+
|
||||
+
|
||||
# Exit handler which ensures processes are cleaned up and, on failure,
|
||||
# prints messages to help developers debug the problem.
|
||||
def _onexit():
|
@ -0,0 +1,61 @@
|
||||
From 4c2f596da5ddb8a1687a4f9c969d5a8dcd2cbcc7 Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Thu, 3 Jun 2021 16:03:07 -0400
|
||||
Subject: [PATCH] Allow kinit with keytab to defer canonicalization
|
||||
|
||||
[ghudson@mit.edu: added tests]
|
||||
|
||||
ticket: 9012 (new)
|
||||
(cherry picked from commit 5e6a6efc5df689d9fb8730d0227167ffbb6ece0e)
|
||||
(cherry picked from commit 090c7319652466339e3e6482bdd1b5a294638dff)
|
||||
---
|
||||
src/clients/kinit/kinit.c | 11 -----------
|
||||
src/tests/t_keytab.py | 13 +++++++++++++
|
||||
2 files changed, 13 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
|
||||
index d1f5d74c3..5a6d7237c 100644
|
||||
--- a/src/clients/kinit/kinit.c
|
||||
+++ b/src/clients/kinit/kinit.c
|
||||
@@ -510,17 +510,6 @@ k5_begin(struct k_opts *opts, struct k5_data *k5)
|
||||
_("when creating default server principal name"));
|
||||
goto cleanup;
|
||||
}
|
||||
- if (k5->me->realm.data[0] == 0) {
|
||||
- ret = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
|
||||
- if (ret == 0) {
|
||||
- com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
|
||||
- _("(principal %s)"), k5->name);
|
||||
- } else {
|
||||
- com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
|
||||
- _("for local services"));
|
||||
- }
|
||||
- goto cleanup;
|
||||
- }
|
||||
} else if (k5->out_cc != NULL) {
|
||||
/* If the output ccache is initialized, use its principal. */
|
||||
if (krb5_cc_get_principal(k5->ctx, k5->out_cc, &princ) == 0)
|
||||
diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py
|
||||
index 850375c92..a9adebb26 100755
|
||||
--- a/src/tests/t_keytab.py
|
||||
+++ b/src/tests/t_keytab.py
|
||||
@@ -41,6 +41,19 @@ realm.kinit(realm.user_princ, flags=['-i'],
|
||||
expected_msg='keytab specified, forcing -k')
|
||||
realm.klist(realm.user_princ)
|
||||
|
||||
+# Test default principal for -k. This operation requires
|
||||
+# canonicalization against the keytab in krb5_get_init_creds_keytab()
|
||||
+# as the krb5_sname_to_principal() result won't have a realm. Try
|
||||
+# with and without without fallback processing since the code paths
|
||||
+# are different.
|
||||
+mark('default principal for -k')
|
||||
+realm.run([kinit, '-k'])
|
||||
+realm.klist(realm.host_princ)
|
||||
+no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}}
|
||||
+no_canon = realm.special_env('no_canon', False, krb5_conf=no_canon_conf)
|
||||
+realm.run([kinit, '-k'], env=no_canon)
|
||||
+realm.klist(realm.host_princ)
|
||||
+
|
||||
# Test extracting keys with multiple key versions present.
|
||||
mark('multi-kvno extract')
|
||||
os.remove(realm.keytab)
|
104
SOURCES/Fix-KCM-flag-transmission-for-remove_cred.patch
Normal file
104
SOURCES/Fix-KCM-flag-transmission-for-remove_cred.patch
Normal file
@ -0,0 +1,104 @@
|
||||
From 92a4b760d741494dacbb4d9db4cf2db9e3b01f2c Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Mon, 29 Mar 2021 14:32:56 -0400
|
||||
Subject: [PATCH] Fix KCM flag transmission for remove_cred
|
||||
|
||||
MIT krb5 uses low bits for KRB5_TC flags, while Heimdal uses high bits
|
||||
so that the same flag word can also hold KRB5_GC flags. Add a mapping
|
||||
function and send the Heimdal flag values when performing a
|
||||
remove_cred operation.
|
||||
|
||||
ticket: 8995
|
||||
(cherry picked from commit 11a82cf424f9c905bb73680c64524f087090d4ef)
|
||||
(cherry picked from commit 04f0de4420508161ce439f262f2761ff51a07ab0)
|
||||
---
|
||||
src/include/kcm.h | 19 +++++++++++++++++++
|
||||
src/lib/krb5/ccache/cc_kcm.c | 36 +++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 54 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/include/kcm.h b/src/include/kcm.h
|
||||
index e4140c3a0..9b66f1cbd 100644
|
||||
--- a/src/include/kcm.h
|
||||
+++ b/src/include/kcm.h
|
||||
@@ -56,8 +56,27 @@
|
||||
* are marshalled as zero-terminated strings. Principals and credentials are
|
||||
* marshalled in the v4 FILE ccache format. UUIDs are 16 bytes. UUID lists
|
||||
* are not delimited, so nothing can come after them.
|
||||
+ *
|
||||
+ * Flag words must use Heimdal flag values, which are not the same as MIT krb5
|
||||
+ * values for KRB5_GC and KRB5_TC constants. The same flag word may contain
|
||||
+ * both kinds of flags in Heimdal, but not in MIT krb5. Defines for the
|
||||
+ * applicable Heimdal flag values are given below using KCM_GC and KCM_TC
|
||||
+ * prefixes.
|
||||
*/
|
||||
|
||||
+#define KCM_GC_CACHED (1U << 0)
|
||||
+
|
||||
+#define KCM_TC_DONT_MATCH_REALM (1U << 31)
|
||||
+#define KCM_TC_MATCH_KEYTYPE (1U << 30)
|
||||
+#define KCM_TC_MATCH_SRV_NAMEONLY (1U << 29)
|
||||
+#define KCM_TC_MATCH_FLAGS_EXACT (1U << 28)
|
||||
+#define KCM_TC_MATCH_FLAGS (1U << 27)
|
||||
+#define KCM_TC_MATCH_TIMES_EXACT (1U << 26)
|
||||
+#define KCM_TC_MATCH_TIMES (1U << 25)
|
||||
+#define KCM_TC_MATCH_AUTHDATA (1U << 24)
|
||||
+#define KCM_TC_MATCH_2ND_TKT (1U << 23)
|
||||
+#define KCM_TC_MATCH_IS_SKEY (1U << 22)
|
||||
+
|
||||
/* Opcodes without comments are currently unused in the MIT client
|
||||
* implementation. */
|
||||
typedef enum kcm_opcode {
|
||||
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||
index 772928e4d..1f81a2190 100644
|
||||
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||
@@ -110,6 +110,40 @@ map_invalid(krb5_error_code code)
|
||||
KRB5_KCM_MALFORMED_REPLY : code;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Map an MIT krb5 KRB5_TC flag word to the equivalent Heimdal flag word. Note
|
||||
+ * that there is no MIT krb5 equivalent for Heimdal's KRB5_TC_DONT_MATCH_REALM
|
||||
+ * (which is like KRB5_TC_MATCH_SRV_NAMEONLY but also applies to the client
|
||||
+ * principal) and no Heimdal equivalent for MIT krb5's KRB5_TC_SUPPORTED_KTYPES
|
||||
+ * (which matches against enctypes from the krb5_context rather than the
|
||||
+ * matching cred).
|
||||
+ */
|
||||
+static inline krb5_flags
|
||||
+map_tcflags(krb5_flags mitflags)
|
||||
+{
|
||||
+ krb5_flags heimflags = 0;
|
||||
+
|
||||
+ if (mitflags & KRB5_TC_MATCH_TIMES)
|
||||
+ heimflags |= KCM_TC_MATCH_TIMES;
|
||||
+ if (mitflags & KRB5_TC_MATCH_IS_SKEY)
|
||||
+ heimflags |= KCM_TC_MATCH_IS_SKEY;
|
||||
+ if (mitflags & KRB5_TC_MATCH_FLAGS)
|
||||
+ heimflags |= KCM_TC_MATCH_FLAGS;
|
||||
+ if (mitflags & KRB5_TC_MATCH_TIMES_EXACT)
|
||||
+ heimflags |= KCM_TC_MATCH_TIMES_EXACT;
|
||||
+ if (mitflags & KRB5_TC_MATCH_FLAGS_EXACT)
|
||||
+ heimflags |= KCM_TC_MATCH_FLAGS_EXACT;
|
||||
+ if (mitflags & KRB5_TC_MATCH_AUTHDATA)
|
||||
+ heimflags |= KCM_TC_MATCH_AUTHDATA;
|
||||
+ if (mitflags & KRB5_TC_MATCH_SRV_NAMEONLY)
|
||||
+ heimflags |= KCM_TC_MATCH_SRV_NAMEONLY;
|
||||
+ if (mitflags & KRB5_TC_MATCH_2ND_TKT)
|
||||
+ heimflags |= KCM_TC_MATCH_2ND_TKT;
|
||||
+ if (mitflags & KRB5_TC_MATCH_KTYPE)
|
||||
+ heimflags |= KCM_TC_MATCH_KEYTYPE;
|
||||
+ return heimflags;
|
||||
+}
|
||||
+
|
||||
/* Begin a request for the given opcode. If cache is non-null, supply the
|
||||
* cache name as a request parameter. */
|
||||
static void
|
||||
@@ -936,7 +970,7 @@ kcm_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags,
|
||||
struct kcmreq req;
|
||||
|
||||
kcmreq_init(&req, KCM_OP_REMOVE_CRED, cache);
|
||||
- k5_buf_add_uint32_be(&req.reqbuf, flags);
|
||||
+ k5_buf_add_uint32_be(&req.reqbuf, map_tcflags(flags));
|
||||
k5_marshal_mcred(&req.reqbuf, mcred);
|
||||
ret = cache_call(context, cache, &req);
|
||||
kcmreq_free(&req);
|
63
SOURCES/Fix-KCM-retrieval-support-for-sssd.patch
Normal file
63
SOURCES/Fix-KCM-retrieval-support-for-sssd.patch
Normal file
@ -0,0 +1,63 @@
|
||||
From b4f3df953015bf6d2d4c973b458f778f31615c11 Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Tue, 11 May 2021 14:04:07 -0400
|
||||
Subject: [PATCH] Fix KCM retrieval support for sssd
|
||||
|
||||
Commit 795ebba8c039be172ab93cd41105c73ffdba0fdb added a retrieval
|
||||
handler using KCM_OP_RETRIEVE, falling back on the same error codes as
|
||||
the previous KCM_OP_GET_CRED_LIST support. But sssd (as of 2.4)
|
||||
returns KRB5_CC_NOSUPP instead of KRB5_CC_IO if it recognizes an
|
||||
opcode but does not implement it. Add a helper function to recognize
|
||||
all known unsupported-opcode error codes, and use it in kcm_retrieve()
|
||||
and kcm_start_seq_get().
|
||||
|
||||
ticket: 8997
|
||||
(cherry picked from commit da103e36e13f3c846bcddbe38dd518a21e5260a0)
|
||||
(cherry picked from commit a5b2cff51808cd86fe8195e7ac074ecd25c3344d)
|
||||
---
|
||||
src/lib/krb5/ccache/cc_kcm.c | 18 ++++++++++++++++--
|
||||
1 file changed, 16 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||
index 23fcf13ea..18505cd3d 100644
|
||||
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||
@@ -144,6 +144,20 @@ map_tcflags(krb5_flags mitflags)
|
||||
return heimflags;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Return true if code could indicate an unsupported operation. Heimdal's KCM
|
||||
+ * returns KRB5_FCC_INTERNAL. sssd's KCM daemon (as of sssd 2.4) returns
|
||||
+ * KRB5_CC_NO_SUPP if it recognizes the operation but does not implement it,
|
||||
+ * and KRB5_CC_IO if it doesn't recognize the operation (which is unfortunate
|
||||
+ * since it could also indicate a communication failure).
|
||||
+ */
|
||||
+static krb5_boolean
|
||||
+unsupported_op_error(krb5_error_code code)
|
||||
+{
|
||||
+ return code == KRB5_FCC_INTERNAL || code == KRB5_CC_IO ||
|
||||
+ code == KRB5_CC_NOSUPP;
|
||||
+}
|
||||
+
|
||||
/* Begin a request for the given opcode. If cache is non-null, supply the
|
||||
* cache name as a request parameter. */
|
||||
static void
|
||||
@@ -841,7 +855,7 @@ kcm_retrieve(krb5_context context, krb5_ccache cache, krb5_flags flags,
|
||||
ret = cache_call(context, cache, &req);
|
||||
|
||||
/* Fall back to iteration if the server does not support retrieval. */
|
||||
- if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
|
||||
+ if (unsupported_op_error(ret)) {
|
||||
ret = k5_cc_retrieve_cred_default(context, cache, flags, mcred,
|
||||
cred_out);
|
||||
goto cleanup;
|
||||
@@ -922,7 +936,7 @@ kcm_start_seq_get(krb5_context context, krb5_ccache cache,
|
||||
ret = kcmreq_get_cred_list(&req, &creds);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
- } else if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
|
||||
+ } else if (unsupported_op_error(ret)) {
|
||||
/* Fall back to GET_CRED_UUID_LIST. */
|
||||
kcmreq_free(&req);
|
||||
kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
|
@ -0,0 +1,47 @@
|
||||
From 0a8dfc380fe3b210662ba1b1d452fcec2f84841b Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Tue, 3 Aug 2021 01:15:27 -0400
|
||||
Subject: [PATCH] Fix KDC null deref on TGS inner body null server
|
||||
|
||||
After the KDC decodes a FAST inner body, it does not check for a null
|
||||
server. Prior to commit 39548a5b17bbda9eeb63625a201cfd19b9de1c5b this
|
||||
would typically result in an error from krb5_unparse_name(), but with
|
||||
the addition of get_local_tgt() it results in a null dereference. Add
|
||||
a null check.
|
||||
|
||||
Reported by Joseph Sutton of Catalyst.
|
||||
|
||||
CVE-2021-37750:
|
||||
|
||||
In MIT krb5 releases 1.14 and later, an authenticated attacker can
|
||||
cause a null dereference in the KDC by sending a FAST TGS request with
|
||||
no server field.
|
||||
|
||||
ticket: 9008 (new)
|
||||
tags: pullup
|
||||
target_version: 1.19-next
|
||||
target_version: 1.18-next
|
||||
|
||||
(cherry picked from commit d775c95af7606a51bf79547a94fa52ddd1cb7f49)
|
||||
(cherry picked from commit bb8fa495d00ccd931eec87a01b8920636cf7903e)
|
||||
(cherry picked from commit dfe383f8251d0edc7e5e08ec5e4fdd9b7f902b2a)
|
||||
---
|
||||
src/kdc/do_tgs_req.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
|
||||
index 463a9c0dd..7c596a111 100644
|
||||
--- a/src/kdc/do_tgs_req.c
|
||||
+++ b/src/kdc/do_tgs_req.c
|
||||
@@ -208,6 +208,11 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
|
||||
status = "FIND_FAST";
|
||||
goto cleanup;
|
||||
}
|
||||
+ if (sprinc == NULL) {
|
||||
+ status = "NULL_SERVER";
|
||||
+ errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
|
||||
errcode = get_local_tgt(kdc_context, &sprinc->realm, header_server,
|
||||
&local_tgt, &local_tgt_storage, &local_tgt_key);
|
114
SOURCES/Fix-KDC-null-deref-on-bad-encrypted-challenge.patch
Normal file
114
SOURCES/Fix-KDC-null-deref-on-bad-encrypted-challenge.patch
Normal file
@ -0,0 +1,114 @@
|
||||
From 3fe94b5854c56da38ba14994b6c371c3e3b9094e Mon Sep 17 00:00:00 2001
|
||||
From: Joseph Sutton <josephsutton@catalyst.net.nz>
|
||||
Date: Wed, 7 Jul 2021 11:47:44 +1200
|
||||
Subject: [PATCH] Fix KDC null deref on bad encrypted challenge
|
||||
|
||||
The function ec_verify() in src/kdc/kdc_preauth_ec.c contains a check
|
||||
to avoid further processing if the armor key is NULL. However, this
|
||||
check is bypassed by a call to k5memdup0() which overwrites retval
|
||||
with 0 if the allocation succeeds. If the armor key is NULL, a call
|
||||
to krb5_c_fx_cf2_simple() will then dereference it, resulting in a
|
||||
crash. Add a check before the k5memdup0() call to avoid overwriting
|
||||
retval.
|
||||
|
||||
CVE-2021-36222:
|
||||
|
||||
In MIT krb5 releases 1.16 and later, an unauthenticated attacker can
|
||||
cause a null dereference in the KDC by sending a request containing a
|
||||
PA-ENCRYPTED-CHALLENGE padata element without using FAST.
|
||||
|
||||
[ghudson@mit.edu: trimmed patch; added test case; edited commit
|
||||
message]
|
||||
|
||||
ticket: 9007 (new)
|
||||
tags: pullup
|
||||
target_version: 1.19-next
|
||||
target_version: 1.18-next
|
||||
|
||||
(cherry picked from commit fc98f520caefff2e5ee9a0026fdf5109944b3562)
|
||||
(cherry picked from commit 791211b00a53b394376d096c881b725ee739a936)
|
||||
---
|
||||
src/kdc/kdc_preauth_ec.c | 3 ++-
|
||||
src/tests/Makefile.in | 1 +
|
||||
src/tests/t_cve-2021-36222.py | 46 +++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 49 insertions(+), 1 deletion(-)
|
||||
create mode 100644 src/tests/t_cve-2021-36222.py
|
||||
|
||||
diff --git a/src/kdc/kdc_preauth_ec.c b/src/kdc/kdc_preauth_ec.c
|
||||
index 7e636b3f9..43a9902cc 100644
|
||||
--- a/src/kdc/kdc_preauth_ec.c
|
||||
+++ b/src/kdc/kdc_preauth_ec.c
|
||||
@@ -87,7 +87,8 @@ ec_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
|
||||
}
|
||||
|
||||
/* Check for a configured FAST ec auth indicator. */
|
||||
- realmstr = k5memdup0(realm.data, realm.length, &retval);
|
||||
+ if (retval == 0)
|
||||
+ realmstr = k5memdup0(realm.data, realm.length, &retval);
|
||||
if (realmstr != NULL)
|
||||
retval = profile_get_string(context->profile, KRB5_CONF_REALMS,
|
||||
realmstr,
|
||||
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
|
||||
index ab416cc5f..20f27d748 100644
|
||||
--- a/src/tests/Makefile.in
|
||||
+++ b/src/tests/Makefile.in
|
||||
@@ -159,6 +159,7 @@ check-pytests: unlockiter s4u2self
|
||||
$(RUNPYTEST) $(srcdir)/t_cve-2012-1015.py $(PYTESTFLAGS)
|
||||
$(RUNPYTEST) $(srcdir)/t_cve-2013-1416.py $(PYTESTFLAGS)
|
||||
$(RUNPYTEST) $(srcdir)/t_cve-2013-1417.py $(PYTESTFLAGS)
|
||||
+ $(RUNPYTEST) $(srcdir)/t_cve-2021-36222.py $(PYTESTFLAGS)
|
||||
$(RM) au.log
|
||||
$(RUNPYTEST) $(srcdir)/t_audit.py $(PYTESTFLAGS)
|
||||
$(RUNPYTEST) $(srcdir)/jsonwalker.py -d $(srcdir)/au_dict.json \
|
||||
diff --git a/src/tests/t_cve-2021-36222.py b/src/tests/t_cve-2021-36222.py
|
||||
new file mode 100644
|
||||
index 000000000..57e04993b
|
||||
--- /dev/null
|
||||
+++ b/src/tests/t_cve-2021-36222.py
|
||||
@@ -0,0 +1,46 @@
|
||||
+import socket
|
||||
+from k5test import *
|
||||
+
|
||||
+realm = K5Realm()
|
||||
+
|
||||
+# CVE-2021-36222 KDC null dereference on encrypted challenge preauth
|
||||
+# without FAST
|
||||
+
|
||||
+s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
+a = (hostname, realm.portbase)
|
||||
+
|
||||
+m = ('6A81A0' '30819D' # [APPLICATION 10] SEQUENCE
|
||||
+ 'A103' '0201' '05' # [1] pvno = 5
|
||||
+ 'A203' '0201' '0A' # [2] msg-type = 10
|
||||
+ 'A30E' '300C' # [3] padata = SEQUENCE OF
|
||||
+ '300A' # SEQUENCE
|
||||
+ 'A104' '0202' '008A' # [1] padata-type = PA-ENCRYPTED-CHALLENGE
|
||||
+ 'A202' '0400' # [2] padata-value = ""
|
||||
+ 'A48180' '307E' # [4] req-body = SEQUENCE
|
||||
+ 'A007' '0305' '0000000000' # [0] kdc-options = 0
|
||||
+ 'A120' '301E' # [1] cname = SEQUENCE
|
||||
+ 'A003' '0201' '01' # [0] name-type = NT-PRINCIPAL
|
||||
+ 'A117' '3015' # [1] name-string = SEQUENCE-OF
|
||||
+ '1B06' '6B7262746774' # krbtgt
|
||||
+ '1B0B' '4B5242544553542E434F4D'
|
||||
+ # KRBTEST.COM
|
||||
+ 'A20D' '1B0B' '4B5242544553542E434F4D'
|
||||
+ # [2] realm = KRBTEST.COM
|
||||
+ 'A320' '301E' # [3] sname = SEQUENCE
|
||||
+ 'A003' '0201' '01' # [0] name-type = NT-PRINCIPAL
|
||||
+ 'A117' '3015' # [1] name-string = SEQUENCE-OF
|
||||
+ '1B06' '6B7262746774' # krbtgt
|
||||
+ '1B0B' '4B5242544553542E434F4D'
|
||||
+ # KRBTEST.COM
|
||||
+ 'A511' '180F' '31393934303631303036303331375A'
|
||||
+ # [5] till = 19940610060317Z
|
||||
+ 'A703' '0201' '00' # [7] nonce = 0
|
||||
+ 'A808' '3006' # [8] etype = SEQUENCE OF
|
||||
+ '020112' '020111') # aes256-cts aes128-cts
|
||||
+
|
||||
+s.sendto(bytes.fromhex(m), a)
|
||||
+
|
||||
+# Make sure kinit still works.
|
||||
+realm.kinit(realm.user_princ, password('user'))
|
||||
+
|
||||
+success('CVE-2021-36222 regression test')
|
58
SOURCES/Fix-k5tls-module-for-OpenSSL-3.patch
Normal file
58
SOURCES/Fix-k5tls-module-for-OpenSSL-3.patch
Normal file
@ -0,0 +1,58 @@
|
||||
From 51938a8b731740299fe47d132b8840edba4141bc Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Sat, 29 May 2021 12:05:49 -0400
|
||||
Subject: [PATCH] Fix k5tls module for OpenSSL 3
|
||||
|
||||
Starting in OpenSSL 3, connection termination without a close_notify
|
||||
alert causes SSL_read() to return SSL_ERROR_SSL instead of
|
||||
SSL_ERROR_SYSCALL. OpenSSL 3 also provides a new option
|
||||
SSL_OP_IGNORE_UNEXPECTED_EOF which allows an application to explicitly
|
||||
ignore possible truncation attacks and receive SSL_ERROR_ZERO_RETURN
|
||||
instead.
|
||||
|
||||
Remove the call to SSL_CTX_get_options() since SSL_CTX_set_options()
|
||||
doesn't clear existing options.
|
||||
|
||||
[ghudson@mit.edu: edited commit message and comment]
|
||||
|
||||
(cherry picked from commit aa9b4a2a64046afd2fab7cb49c346295874a5fb6)
|
||||
(cherry picked from commit 201e38845e9f70234bcaa9ba7c25b28e38169b0a)
|
||||
---
|
||||
src/plugins/tls/k5tls/openssl.c | 17 ++++++++++++++---
|
||||
1 file changed, 14 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/plugins/tls/k5tls/openssl.c b/src/plugins/tls/k5tls/openssl.c
|
||||
index 76a43b3cd..99fda7ffc 100644
|
||||
--- a/src/plugins/tls/k5tls/openssl.c
|
||||
+++ b/src/plugins/tls/k5tls/openssl.c
|
||||
@@ -433,7 +433,7 @@ setup(krb5_context context, SOCKET fd, const char *servername,
|
||||
char **anchors, k5_tls_handle *handle_out)
|
||||
{
|
||||
int e;
|
||||
- long options;
|
||||
+ long options = SSL_OP_NO_SSLv2;
|
||||
SSL_CTX *ctx = NULL;
|
||||
SSL *ssl = NULL;
|
||||
k5_tls_handle handle = NULL;
|
||||
@@ -448,8 +448,19 @@ setup(krb5_context context, SOCKET fd, const char *servername,
|
||||
ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (ctx == NULL)
|
||||
goto error;
|
||||
- options = SSL_CTX_get_options(ctx);
|
||||
- SSL_CTX_set_options(ctx, options | SSL_OP_NO_SSLv2);
|
||||
+
|
||||
+#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
|
||||
+ /*
|
||||
+ * For OpenSSL 3 and later, mark close_notify alerts as optional. We don't
|
||||
+ * need to worry about truncation attacks because the protocols this module
|
||||
+ * is used with (Kerberos and change-password) receive a single
|
||||
+ * length-delimited message from the server. For prior versions of OpenSSL
|
||||
+ * we check for SSL_ERROR_SYSCALL when reading instead (this error changes
|
||||
+ * to SSL_ERROR_SSL in OpenSSL 3).
|
||||
+ */
|
||||
+ options |= SSL_OP_IGNORE_UNEXPECTED_EOF;
|
||||
+#endif
|
||||
+ SSL_CTX_set_options(ctx, options);
|
||||
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
|
||||
X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), 0);
|
65
SOURCES/Fix-kadmin-k-with-fallback-or-referral-realm.patch
Normal file
65
SOURCES/Fix-kadmin-k-with-fallback-or-referral-realm.patch
Normal file
@ -0,0 +1,65 @@
|
||||
From ddbd548562d951d327a10c9dcb975418427f6fea Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Mon, 7 Jun 2021 15:00:41 -0400
|
||||
Subject: [PATCH] Fix kadmin -k with fallback or referral realm
|
||||
|
||||
kadmin -k produces a client principal name with
|
||||
krb5_sname_to_principal(), but it gets converted to a string and back
|
||||
due to the signature of kadm5_init_with_skey(), which loses track of
|
||||
the name type, so no canonicalization is performed.
|
||||
|
||||
In libkadm5clnt initialization, recognize the important subset of this
|
||||
case--an empty realm indicates either fallback processing or the
|
||||
referral realm--and restore the host-based name type so that the
|
||||
client principal can be canonicalized against the keytab.
|
||||
|
||||
ticket: 9013 (new)
|
||||
(cherry picked from commit dcb79089276624d7ddf44e08d35bd6d7d7e557d2)
|
||||
(cherry picked from commit cd8ff035f5b4720a8fc457355726f7bd0eab5eaa)
|
||||
---
|
||||
src/lib/kadm5/clnt/client_init.c | 7 +++++++
|
||||
src/tests/t_kadmin.py | 12 ++++++++++++
|
||||
2 files changed, 19 insertions(+)
|
||||
|
||||
diff --git a/src/lib/kadm5/clnt/client_init.c b/src/lib/kadm5/clnt/client_init.c
|
||||
index aa1223bb3..0aaca701f 100644
|
||||
--- a/src/lib/kadm5/clnt/client_init.c
|
||||
+++ b/src/lib/kadm5/clnt/client_init.c
|
||||
@@ -221,9 +221,16 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
|
||||
return KADM5_MISSING_KRB5_CONF_PARAMS;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * Parse the client name. If it has an empty realm, it is almost certainly
|
||||
+ * a host-based principal using DNS fallback processing or the referral
|
||||
+ * realm, so give it the appropriate name type for canonicalization.
|
||||
+ */
|
||||
code = krb5_parse_name(handle->context, client_name, &client);
|
||||
if (code)
|
||||
goto error;
|
||||
+ if (init_type == INIT_SKEY && client->realm.length == 0)
|
||||
+ client->type = KRB5_NT_SRV_HST;
|
||||
|
||||
/*
|
||||
* Get credentials. Also does some fallbacks in case kadmin/fqdn
|
||||
diff --git a/src/tests/t_kadmin.py b/src/tests/t_kadmin.py
|
||||
index fe6a3cc2e..98453d92e 100644
|
||||
--- a/src/tests/t_kadmin.py
|
||||
+++ b/src/tests/t_kadmin.py
|
||||
@@ -51,4 +51,16 @@ for i in range(200):
|
||||
realm.run_kadmin(['addprinc', '-randkey', 'foo%d' % i])
|
||||
realm.run_kadmin(['listprincs'], expected_msg='foo199')
|
||||
|
||||
+# Test kadmin -k with the default principal, with and without
|
||||
+# fallback. This operation requires canonicalization against the
|
||||
+# keytab in krb5_get_init_creds_keytab() as the
|
||||
+# krb5_sname_to_principal() result won't have a realm. Try with and
|
||||
+# without without fallback processing since the code paths are
|
||||
+# different.
|
||||
+mark('kadmin -k')
|
||||
+realm.run([kadmin, '-k', 'getprinc', realm.host_princ])
|
||||
+no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}}
|
||||
+no_canon = realm.special_env('no_canon', False, krb5_conf=no_canon_conf)
|
||||
+realm.run([kadmin, '-k', 'getprinc', realm.host_princ], env=no_canon)
|
||||
+
|
||||
success('kadmin and kpasswd tests')
|
552
SOURCES/Fix-softpkcs11-build-issues-with-openssl-3.0.patch
Normal file
552
SOURCES/Fix-softpkcs11-build-issues-with-openssl-3.0.patch
Normal file
@ -0,0 +1,552 @@
|
||||
From f85a818fe1a7438db7e1ea579818da67e0be017d Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Sat, 15 May 2021 17:35:25 -0400
|
||||
Subject: [PATCH] Fix softpkcs11 build issues with openssl 3.0
|
||||
|
||||
EVP_PKEY_get0_RSA() has been modified to have const return type. Remove
|
||||
its usages in favor of the EVP_PKEY interface. Also remove calls to
|
||||
RSA_blinding_off(), which we don't need and would require a non-const
|
||||
object. Similarly, remove RSA_set_method() calls that set a pre-existing
|
||||
default.
|
||||
|
||||
Since softpkcs11 doesn't link against krb5 and can't use zap(), allocate
|
||||
buffers with OPENSSL_malloc() so can use OPENSSL_clear_free().
|
||||
|
||||
Move several argument validation checks to the top of their functions.
|
||||
|
||||
Fix some incorrect/inconsistent log messages.
|
||||
|
||||
(cherry picked from commit 00de1aad7b3647b91017c7009b0bc65cd0c8b2e0)
|
||||
(cherry picked from commit a86b780ef275b35e8dc1e6d1886ec8e8d941f7c4)
|
||||
---
|
||||
src/tests/softpkcs11/main.c | 360 ++++++++++++++----------------------
|
||||
1 file changed, 141 insertions(+), 219 deletions(-)
|
||||
|
||||
diff --git a/src/tests/softpkcs11/main.c b/src/tests/softpkcs11/main.c
|
||||
index 1cccdfb43..caa537b68 100644
|
||||
--- a/src/tests/softpkcs11/main.c
|
||||
+++ b/src/tests/softpkcs11/main.c
|
||||
@@ -375,10 +375,9 @@ add_st_object(void)
|
||||
return NULL;
|
||||
soft_token.object.objs = objs;
|
||||
|
||||
- o = malloc(sizeof(*o));
|
||||
+ o = calloc(1, sizeof(*o));
|
||||
if (o == NULL)
|
||||
return NULL;
|
||||
- memset(o, 0, sizeof(*o));
|
||||
o->attrs = NULL;
|
||||
o->num_attributes = 0;
|
||||
o->object_handle = soft_token.object.num_objs;
|
||||
@@ -424,7 +423,7 @@ add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
|
||||
CK_ULONG modulus_bits = 0;
|
||||
CK_BYTE *exponent = NULL;
|
||||
size_t exponent_len = 0;
|
||||
- RSA *rsa;
|
||||
+ const RSA *rsa;
|
||||
const BIGNUM *n, *e;
|
||||
|
||||
rsa = EVP_PKEY_get0_RSA(key);
|
||||
@@ -445,8 +444,6 @@ add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
|
||||
add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
|
||||
exponent, exponent_len);
|
||||
|
||||
- RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
|
||||
-
|
||||
free(modulus);
|
||||
free(exponent);
|
||||
}
|
||||
@@ -679,10 +676,6 @@ add_certificate(char *label,
|
||||
} else {
|
||||
/* XXX verify keytype */
|
||||
|
||||
- if (key_type == CKK_RSA)
|
||||
- RSA_set_method(EVP_PKEY_get0_RSA(o->u.private_key.key),
|
||||
- RSA_PKCS1_OpenSSL());
|
||||
-
|
||||
if (X509_check_private_key(cert, o->u.private_key.key) != 1) {
|
||||
EVP_PKEY_free(o->u.private_key.key);
|
||||
o->u.private_key.key = NULL;
|
||||
@@ -695,7 +688,7 @@ add_certificate(char *label,
|
||||
}
|
||||
|
||||
ret = CKR_OK;
|
||||
- out:
|
||||
+out:
|
||||
if (ret != CKR_OK) {
|
||||
st_logf("something went wrong when adding cert!\n");
|
||||
|
||||
@@ -1224,8 +1217,6 @@ C_Login(CK_SESSION_HANDLE hSession,
|
||||
}
|
||||
|
||||
/* XXX check keytype */
|
||||
- RSA_set_method(EVP_PKEY_get0_RSA(o->u.private_key.key),
|
||||
- RSA_PKCS1_OpenSSL());
|
||||
|
||||
if (X509_check_private_key(o->u.private_key.cert, o->u.private_key.key) != 1) {
|
||||
EVP_PKEY_free(o->u.private_key.key);
|
||||
@@ -1495,8 +1486,9 @@ C_Encrypt(CK_SESSION_HANDLE hSession,
|
||||
struct st_object *o;
|
||||
void *buffer = NULL;
|
||||
CK_RV ret;
|
||||
- RSA *rsa;
|
||||
- int padding, len, buffer_len, padding_len;
|
||||
+ size_t buffer_len = 0;
|
||||
+ int padding;
|
||||
+ EVP_PKEY_CTX *ctx = NULL;
|
||||
|
||||
st_logf("Encrypt\n");
|
||||
|
||||
@@ -1512,70 +1504,58 @@ C_Encrypt(CK_SESSION_HANDLE hSession,
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
- rsa = EVP_PKEY_get0_RSA(o->u.public_key);
|
||||
-
|
||||
- if (rsa == NULL)
|
||||
- return CKR_ARGUMENTS_BAD;
|
||||
-
|
||||
- RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
|
||||
-
|
||||
- buffer_len = RSA_size(rsa);
|
||||
-
|
||||
- buffer = malloc(buffer_len);
|
||||
- if (buffer == NULL) {
|
||||
- ret = CKR_DEVICE_MEMORY;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- ret = CKR_OK;
|
||||
- switch(state->encrypt_mechanism->mechanism) {
|
||||
- case CKM_RSA_PKCS:
|
||||
- padding = RSA_PKCS1_PADDING;
|
||||
- padding_len = RSA_PKCS1_PADDING_SIZE;
|
||||
- break;
|
||||
- case CKM_RSA_X_509:
|
||||
- padding = RSA_NO_PADDING;
|
||||
- padding_len = 0;
|
||||
- break;
|
||||
- default:
|
||||
- ret = CKR_FUNCTION_NOT_SUPPORTED;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- if ((CK_ULONG)buffer_len + padding_len < ulDataLen) {
|
||||
- ret = CKR_ARGUMENTS_BAD;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
if (pulEncryptedDataLen == NULL) {
|
||||
st_logf("pulEncryptedDataLen NULL\n");
|
||||
ret = CKR_ARGUMENTS_BAD;
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (pData == NULL_PTR) {
|
||||
+ if (pData == NULL) {
|
||||
st_logf("data NULL\n");
|
||||
ret = CKR_ARGUMENTS_BAD;
|
||||
goto out;
|
||||
}
|
||||
|
||||
- len = RSA_public_encrypt(ulDataLen, pData, buffer, rsa, padding);
|
||||
- if (len <= 0) {
|
||||
+ switch(state->encrypt_mechanism->mechanism) {
|
||||
+ case CKM_RSA_PKCS:
|
||||
+ padding = RSA_PKCS1_PADDING;
|
||||
+ break;
|
||||
+ case CKM_RSA_X_509:
|
||||
+ padding = RSA_NO_PADDING;
|
||||
+ break;
|
||||
+ default:
|
||||
+ ret = CKR_FUNCTION_NOT_SUPPORTED;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ctx = EVP_PKEY_CTX_new(o->u.public_key, NULL);
|
||||
+ if (ctx == NULL || EVP_PKEY_encrypt_init(ctx) <= 0 ||
|
||||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
|
||||
+ EVP_PKEY_encrypt(ctx, NULL, &buffer_len, pData, ulDataLen) <= 0) {
|
||||
ret = CKR_DEVICE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
- if (len > buffer_len)
|
||||
- abort();
|
||||
|
||||
- if (pEncryptedData != NULL_PTR)
|
||||
- memcpy(pEncryptedData, buffer, len);
|
||||
- *pulEncryptedDataLen = len;
|
||||
-
|
||||
- out:
|
||||
- if (buffer) {
|
||||
- memset(buffer, 0, buffer_len);
|
||||
- free(buffer);
|
||||
+ buffer = OPENSSL_malloc(buffer_len);
|
||||
+ if (buffer == NULL) {
|
||||
+ ret = CKR_DEVICE_MEMORY;
|
||||
+ goto out;
|
||||
}
|
||||
+
|
||||
+ if (EVP_PKEY_encrypt(ctx, buffer, &buffer_len, pData, ulDataLen) <= 0) {
|
||||
+ ret = CKR_DEVICE_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ st_logf("Encrypt done\n");
|
||||
+
|
||||
+ if (pEncryptedData != NULL)
|
||||
+ memcpy(pEncryptedData, buffer, buffer_len);
|
||||
+ *pulEncryptedDataLen = buffer_len;
|
||||
+
|
||||
+ ret = CKR_OK;
|
||||
+out:
|
||||
+ OPENSSL_clear_free(buffer, buffer_len);
|
||||
+ EVP_PKEY_CTX_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1646,8 +1626,9 @@ C_Decrypt(CK_SESSION_HANDLE hSession,
|
||||
struct st_object *o;
|
||||
void *buffer = NULL;
|
||||
CK_RV ret;
|
||||
- RSA *rsa;
|
||||
- int padding, len, buffer_len, padding_len;
|
||||
+ size_t buffer_len = 0;
|
||||
+ int padding;
|
||||
+ EVP_PKEY_CTX *ctx = NULL;
|
||||
|
||||
st_logf("Decrypt\n");
|
||||
|
||||
@@ -1663,41 +1644,6 @@ C_Decrypt(CK_SESSION_HANDLE hSession,
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
- rsa = EVP_PKEY_get0_RSA(o->u.private_key.key);
|
||||
-
|
||||
- if (rsa == NULL)
|
||||
- return CKR_ARGUMENTS_BAD;
|
||||
-
|
||||
- RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
|
||||
-
|
||||
- buffer_len = RSA_size(rsa);
|
||||
-
|
||||
- buffer = malloc(buffer_len);
|
||||
- if (buffer == NULL) {
|
||||
- ret = CKR_DEVICE_MEMORY;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- ret = CKR_OK;
|
||||
- switch(state->decrypt_mechanism->mechanism) {
|
||||
- case CKM_RSA_PKCS:
|
||||
- padding = RSA_PKCS1_PADDING;
|
||||
- padding_len = RSA_PKCS1_PADDING_SIZE;
|
||||
- break;
|
||||
- case CKM_RSA_X_509:
|
||||
- padding = RSA_NO_PADDING;
|
||||
- padding_len = 0;
|
||||
- break;
|
||||
- default:
|
||||
- ret = CKR_FUNCTION_NOT_SUPPORTED;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- if ((CK_ULONG)buffer_len + padding_len < ulEncryptedDataLen) {
|
||||
- ret = CKR_ARGUMENTS_BAD;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
if (pulDataLen == NULL) {
|
||||
st_logf("pulDataLen NULL\n");
|
||||
ret = CKR_ARGUMENTS_BAD;
|
||||
@@ -1710,24 +1656,48 @@ C_Decrypt(CK_SESSION_HANDLE hSession,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- len = RSA_private_decrypt(ulEncryptedDataLen, pEncryptedData, buffer,
|
||||
- rsa, padding);
|
||||
- if (len <= 0) {
|
||||
+ switch(state->decrypt_mechanism->mechanism) {
|
||||
+ case CKM_RSA_PKCS:
|
||||
+ padding = RSA_PKCS1_PADDING;
|
||||
+ break;
|
||||
+ case CKM_RSA_X_509:
|
||||
+ padding = RSA_NO_PADDING;
|
||||
+ break;
|
||||
+ default:
|
||||
+ ret = CKR_FUNCTION_NOT_SUPPORTED;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ctx = EVP_PKEY_CTX_new(o->u.private_key.key, NULL);
|
||||
+ if (ctx == NULL || EVP_PKEY_decrypt_init(ctx) <= 0 ||
|
||||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
|
||||
+ EVP_PKEY_decrypt(ctx, NULL, &buffer_len, pEncryptedData,
|
||||
+ ulEncryptedDataLen) <= 0) {
|
||||
ret = CKR_DEVICE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
- if (len > buffer_len)
|
||||
- abort();
|
||||
+
|
||||
+ buffer = OPENSSL_malloc(buffer_len);
|
||||
+ if (buffer == NULL) {
|
||||
+ ret = CKR_DEVICE_MEMORY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (EVP_PKEY_decrypt(ctx, buffer, &buffer_len, pEncryptedData,
|
||||
+ ulEncryptedDataLen) <= 0) {
|
||||
+ ret = CKR_DEVICE_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ st_logf("Decrypt done\n");
|
||||
|
||||
if (pData != NULL_PTR)
|
||||
- memcpy(pData, buffer, len);
|
||||
- *pulDataLen = len;
|
||||
+ memcpy(pData, buffer, buffer_len);
|
||||
+ *pulDataLen = buffer_len;
|
||||
|
||||
- out:
|
||||
- if (buffer) {
|
||||
- memset(buffer, 0, buffer_len);
|
||||
- free(buffer);
|
||||
- }
|
||||
+ ret = CKR_OK;
|
||||
+out:
|
||||
+ OPENSSL_clear_free(buffer, buffer_len);
|
||||
+ EVP_PKEY_CTX_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1806,8 +1776,9 @@ C_Sign(CK_SESSION_HANDLE hSession,
|
||||
struct st_object *o;
|
||||
void *buffer = NULL;
|
||||
CK_RV ret;
|
||||
- RSA *rsa;
|
||||
- int padding, len, buffer_len, padding_len;
|
||||
+ int padding;
|
||||
+ size_t buffer_len = 0;
|
||||
+ EVP_PKEY_CTX *ctx = NULL;
|
||||
|
||||
st_logf("Sign\n");
|
||||
VERIFY_SESSION_HANDLE(hSession, &state);
|
||||
@@ -1822,40 +1793,6 @@ C_Sign(CK_SESSION_HANDLE hSession,
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
- rsa = EVP_PKEY_get0_RSA(o->u.private_key.key);
|
||||
-
|
||||
- if (rsa == NULL)
|
||||
- return CKR_ARGUMENTS_BAD;
|
||||
-
|
||||
- RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
|
||||
-
|
||||
- buffer_len = RSA_size(rsa);
|
||||
-
|
||||
- buffer = malloc(buffer_len);
|
||||
- if (buffer == NULL) {
|
||||
- ret = CKR_DEVICE_MEMORY;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- switch(state->sign_mechanism->mechanism) {
|
||||
- case CKM_RSA_PKCS:
|
||||
- padding = RSA_PKCS1_PADDING;
|
||||
- padding_len = RSA_PKCS1_PADDING_SIZE;
|
||||
- break;
|
||||
- case CKM_RSA_X_509:
|
||||
- padding = RSA_NO_PADDING;
|
||||
- padding_len = 0;
|
||||
- break;
|
||||
- default:
|
||||
- ret = CKR_FUNCTION_NOT_SUPPORTED;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- if ((CK_ULONG)buffer_len < ulDataLen + padding_len) {
|
||||
- ret = CKR_ARGUMENTS_BAD;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
if (pulSignatureLen == NULL) {
|
||||
st_logf("signature len NULL\n");
|
||||
ret = CKR_ARGUMENTS_BAD;
|
||||
@@ -1868,26 +1805,46 @@ C_Sign(CK_SESSION_HANDLE hSession,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- len = RSA_private_encrypt(ulDataLen, pData, buffer, rsa, padding);
|
||||
- st_logf("private encrypt done\n");
|
||||
- if (len <= 0) {
|
||||
+ switch(state->sign_mechanism->mechanism) {
|
||||
+ case CKM_RSA_PKCS:
|
||||
+ padding = RSA_PKCS1_PADDING;
|
||||
+ break;
|
||||
+ case CKM_RSA_X_509:
|
||||
+ padding = RSA_NO_PADDING;
|
||||
+ break;
|
||||
+ default:
|
||||
+ ret = CKR_FUNCTION_NOT_SUPPORTED;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ctx = EVP_PKEY_CTX_new(o->u.private_key.key, NULL);
|
||||
+ if (ctx == NULL || EVP_PKEY_sign_init(ctx) <= 0 ||
|
||||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
|
||||
+ EVP_PKEY_sign(ctx, NULL, &buffer_len, pData, ulDataLen) <= 0) {
|
||||
ret = CKR_DEVICE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
- if (len > buffer_len)
|
||||
- abort();
|
||||
|
||||
- if (pSignature != NULL_PTR)
|
||||
- memcpy(pSignature, buffer, len);
|
||||
- *pulSignatureLen = len;
|
||||
+ buffer = OPENSSL_malloc(buffer_len);
|
||||
+ if (buffer == NULL) {
|
||||
+ ret = CKR_DEVICE_MEMORY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (EVP_PKEY_sign(ctx, buffer, &buffer_len, pData, ulDataLen) <= 0) {
|
||||
+ ret = CKR_DEVICE_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ st_logf("Sign done\n");
|
||||
+
|
||||
+ if (pSignature != NULL)
|
||||
+ memcpy(pSignature, buffer, buffer_len);
|
||||
+ *pulSignatureLen = buffer_len;
|
||||
|
||||
ret = CKR_OK;
|
||||
-
|
||||
- out:
|
||||
- if (buffer) {
|
||||
- memset(buffer, 0, buffer_len);
|
||||
- free(buffer);
|
||||
- }
|
||||
+out:
|
||||
+ OPENSSL_clear_free(buffer, buffer_len);
|
||||
+ EVP_PKEY_CTX_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1951,10 +1908,9 @@ C_Verify(CK_SESSION_HANDLE hSession,
|
||||
{
|
||||
struct session_state *state;
|
||||
struct st_object *o;
|
||||
- void *buffer = NULL;
|
||||
CK_RV ret;
|
||||
- RSA *rsa;
|
||||
- int padding, len, buffer_len;
|
||||
+ int padding;
|
||||
+ EVP_PKEY_CTX *ctx = NULL;
|
||||
|
||||
st_logf("Verify\n");
|
||||
VERIFY_SESSION_HANDLE(hSession, &state);
|
||||
@@ -1969,39 +1925,6 @@ C_Verify(CK_SESSION_HANDLE hSession,
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
- rsa = EVP_PKEY_get0_RSA(o->u.public_key);
|
||||
-
|
||||
- if (rsa == NULL)
|
||||
- return CKR_ARGUMENTS_BAD;
|
||||
-
|
||||
- RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
|
||||
-
|
||||
- buffer_len = RSA_size(rsa);
|
||||
-
|
||||
- buffer = malloc(buffer_len);
|
||||
- if (buffer == NULL) {
|
||||
- ret = CKR_DEVICE_MEMORY;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- ret = CKR_OK;
|
||||
- switch(state->verify_mechanism->mechanism) {
|
||||
- case CKM_RSA_PKCS:
|
||||
- padding = RSA_PKCS1_PADDING;
|
||||
- break;
|
||||
- case CKM_RSA_X_509:
|
||||
- padding = RSA_NO_PADDING;
|
||||
- break;
|
||||
- default:
|
||||
- ret = CKR_FUNCTION_NOT_SUPPORTED;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- if ((CK_ULONG)buffer_len < ulDataLen) {
|
||||
- ret = CKR_ARGUMENTS_BAD;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
if (pSignature == NULL) {
|
||||
st_logf("signature NULL\n");
|
||||
ret = CKR_ARGUMENTS_BAD;
|
||||
@@ -2014,34 +1937,34 @@ C_Verify(CK_SESSION_HANDLE hSession,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- len = RSA_public_decrypt(ulDataLen, pData, buffer, rsa, padding);
|
||||
- st_logf("private encrypt done\n");
|
||||
- if (len <= 0) {
|
||||
+ switch(state->verify_mechanism->mechanism) {
|
||||
+ case CKM_RSA_PKCS:
|
||||
+ padding = RSA_PKCS1_PADDING;
|
||||
+ break;
|
||||
+ case CKM_RSA_X_509:
|
||||
+ padding = RSA_NO_PADDING;
|
||||
+ break;
|
||||
+ default:
|
||||
+ ret = CKR_FUNCTION_NOT_SUPPORTED;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ctx = EVP_PKEY_CTX_new(o->u.public_key, NULL);
|
||||
+ if (ctx == NULL || EVP_PKEY_verify_init(ctx) <= 0 ||
|
||||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 ||
|
||||
+ EVP_PKEY_verify(ctx, pSignature, ulSignatureLen, pData,
|
||||
+ ulDataLen) <= 0) {
|
||||
ret = CKR_DEVICE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
- if (len > buffer_len)
|
||||
- abort();
|
||||
+ st_logf("Verify done\n");
|
||||
|
||||
- if ((CK_ULONG)len != ulSignatureLen) {
|
||||
- ret = CKR_GENERAL_ERROR;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- if (memcmp(pSignature, buffer, len) != 0) {
|
||||
- ret = CKR_GENERAL_ERROR;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- out:
|
||||
- if (buffer) {
|
||||
- memset(buffer, 0, buffer_len);
|
||||
- free(buffer);
|
||||
- }
|
||||
+ ret = CKR_OK;
|
||||
+out:
|
||||
+ EVP_PKEY_CTX_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
-
|
||||
CK_RV
|
||||
C_VerifyUpdate(CK_SESSION_HANDLE hSession,
|
||||
CK_BYTE_PTR pPart,
|
||||
@@ -2072,7 +1995,6 @@ C_GenerateRandom(CK_SESSION_HANDLE hSession,
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
-
|
||||
CK_FUNCTION_LIST funcs = {
|
||||
{ 2, 11 },
|
||||
C_Initialize,
|
@ -0,0 +1,97 @@
|
||||
From 8f70ad82a645ccb7fb1677d260baa5e4112890d4 Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Mon, 7 Jun 2021 13:27:29 -0400
|
||||
Subject: [PATCH] Fix some principal realm canonicalization cases
|
||||
|
||||
The no_hostrealm and subst_defrealm flags in struct canonprinc were
|
||||
only applied when dns_canonicalize_hostname=fallback; in the other
|
||||
cases, the initial krb5_sname_to_principal() result is treated as
|
||||
canonical. For no_hostrealm this limitation doesn't currently matter,
|
||||
because all uses pass a principal with no realm as input. However,
|
||||
subst_defrealm is used to convert the referral realm to the default
|
||||
realm in krb5_get_init_creds_keytab(), krb5_cc_cache_match(), and
|
||||
gss_acquire_cred() when it needs to check the desired name against a
|
||||
specified ccache.
|
||||
|
||||
In k5_canonprinc(), if the input principal is a
|
||||
krb5_sname_to_principal() result and fallback isn't in effect, apply
|
||||
subst_defrealm. Document in os-proto.h that no_hostrealm doesn't
|
||||
remove an existing realm and that krb5_sname_to_principal() may
|
||||
already have looked one up.
|
||||
|
||||
ticket: 9011 (new)
|
||||
(cherry picked from commit c077d0c6430c4ac163443aacc03d14d206a4cbb8)
|
||||
(cherry picked from commit 5ae9bc98f23aeaa2ce17debe5a9b0cf1130e54ed)
|
||||
---
|
||||
src/lib/krb5/os/os-proto.h | 13 +++++++++----
|
||||
src/lib/krb5/os/sn2princ.c | 24 +++++++++++++++++++++---
|
||||
2 files changed, 30 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
|
||||
index 7d5e7978f..a985f2aec 100644
|
||||
--- a/src/lib/krb5/os/os-proto.h
|
||||
+++ b/src/lib/krb5/os/os-proto.h
|
||||
@@ -85,10 +85,15 @@ struct sendto_callback_info {
|
||||
|
||||
/*
|
||||
* Initialize with all zeros except for princ. Set no_hostrealm to disable
|
||||
- * host-to-realm lookup, which ordinarily happens after canonicalizing the host
|
||||
- * part. Set subst_defrealm to substitute the default realm for the referral
|
||||
- * realm after realm lookup (this has no effect if no_hostrealm is set). Free
|
||||
- * with free_canonprinc() when done.
|
||||
+ * host-to-realm lookup, which ordinarily happens during fallback processing
|
||||
+ * after canonicalizing the host part. Set subst_defrealm to substitute the
|
||||
+ * default realm for the referral realm after realm lookup. Do not set both
|
||||
+ * flags. Free with free_canonprinc() when done.
|
||||
+ *
|
||||
+ * no_hostrealm only applies if fallback processing is in use
|
||||
+ * (dns_canonicalize_hostname = fallback). It will not remove the realm if
|
||||
+ * krb5_sname_to_principal() already canonicalized the hostname and looked up a
|
||||
+ * realm. subst_defrealm applies whether or not fallback processing is in use.
|
||||
*/
|
||||
struct canonprinc {
|
||||
krb5_const_principal princ;
|
||||
diff --git a/src/lib/krb5/os/sn2princ.c b/src/lib/krb5/os/sn2princ.c
|
||||
index c99b7da17..93c155932 100644
|
||||
--- a/src/lib/krb5/os/sn2princ.c
|
||||
+++ b/src/lib/krb5/os/sn2princ.c
|
||||
@@ -271,18 +271,36 @@ krb5_error_code
|
||||
k5_canonprinc(krb5_context context, struct canonprinc *iter,
|
||||
krb5_const_principal *princ_out)
|
||||
{
|
||||
+ krb5_error_code ret;
|
||||
int step = ++iter->step;
|
||||
|
||||
*princ_out = NULL;
|
||||
|
||||
- /* If we're not doing fallback, the input principal is canonical. */
|
||||
- if (context->dns_canonicalize_hostname != CANONHOST_FALLBACK ||
|
||||
- iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2 ||
|
||||
+ /* If the hostname isn't from krb5_sname_to_principal(), the input
|
||||
+ * principal is canonical. */
|
||||
+ if (iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2 ||
|
||||
iter->princ->data[1].length == 0) {
|
||||
*princ_out = (step == 1) ? iter->princ : NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ /* If we're not doing fallback, the hostname is canonical, but we may need
|
||||
+ * to substitute the default realm. */
|
||||
+ if (context->dns_canonicalize_hostname != CANONHOST_FALLBACK) {
|
||||
+ if (step > 1)
|
||||
+ return 0;
|
||||
+ iter->copy = *iter->princ;
|
||||
+ if (iter->subst_defrealm && iter->copy.realm.length == 0) {
|
||||
+ ret = krb5_get_default_realm(context, &iter->realm);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ iter->copy = *iter->princ;
|
||||
+ iter->copy.realm = string2data(iter->realm);
|
||||
+ }
|
||||
+ *princ_out = &iter->copy;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
/* Canonicalize without DNS at step 1, with DNS at step 2. */
|
||||
if (step > 2)
|
||||
return 0;
|
301
SOURCES/Handle-OpenSSL-3-s-providers.patch
Normal file
301
SOURCES/Handle-OpenSSL-3-s-providers.patch
Normal file
@ -0,0 +1,301 @@
|
||||
From e3f3d31a3db23f6c8437cd0efe45f67a7f4fc6aa Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Sat, 15 May 2021 21:18:06 -0400
|
||||
Subject: [PATCH] Handle OpenSSL 3's providers
|
||||
|
||||
OpenSSL 3 compartmentalizes what algorithms it uses, which for us means
|
||||
another hoop to jump through to use dubious cryptography. (Right now,
|
||||
we need to load "legacy" in order to access MD4 and RC4.)
|
||||
|
||||
Use our normal initializer logic to set up providers both in the OpenSSL
|
||||
provider an the PKINIT plugin. Since DT_FINI is too late, release them
|
||||
using atexit() as OpenSSL does.
|
||||
|
||||
(cherry picked from commit bea5a703a06da1f1ab56821b77a2d3661cb0dda4)
|
||||
[rharwood@redhat.com: work around des3 removal and rc4 fips changes]
|
||||
---
|
||||
src/configure.ac | 1 +
|
||||
src/lib/crypto/openssl/enc_provider/aes.c | 16 ++++++
|
||||
.../crypto/openssl/enc_provider/camellia.c | 16 ++++++
|
||||
src/lib/crypto/openssl/enc_provider/rc4.c | 4 ++
|
||||
.../crypto/openssl/hash_provider/hash_evp.c | 5 ++
|
||||
src/lib/crypto/openssl/init.c | 53 +++++++++++++++++++
|
||||
src/plugins/preauth/pkinit/Makefile.in | 1 +
|
||||
.../preauth/pkinit/pkinit_crypto_openssl.c | 33 ++++++++++--
|
||||
8 files changed, 126 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/configure.ac b/src/configure.ac
|
||||
index 9c2e816fe..20066918b 100644
|
||||
--- a/src/configure.ac
|
||||
+++ b/src/configure.ac
|
||||
@@ -284,6 +284,7 @@ AC_SUBST(CRYPTO_IMPL_LIBS)
|
||||
|
||||
if test "$CRYPTO_IMPL" = openssl; then
|
||||
AC_CHECK_FUNCS(EVP_KDF_fetch)
|
||||
+ AC_CHECK_FUNCS(OSSL_PROVIDER_load)
|
||||
fi
|
||||
|
||||
AC_ARG_WITH([prng-alg],
|
||||
diff --git a/src/lib/crypto/openssl/enc_provider/aes.c b/src/lib/crypto/openssl/enc_provider/aes.c
|
||||
index 6b4622fe9..31c90a69d 100644
|
||||
--- a/src/lib/crypto/openssl/enc_provider/aes.c
|
||||
+++ b/src/lib/crypto/openssl/enc_provider/aes.c
|
||||
@@ -68,6 +68,10 @@ cbc_enc(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
struct iov_cursor cursor;
|
||||
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
if (ctx == NULL)
|
||||
return ENOMEM;
|
||||
@@ -102,6 +106,10 @@ cbc_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
struct iov_cursor cursor;
|
||||
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
if (ctx == NULL)
|
||||
return ENOMEM;
|
||||
@@ -137,6 +145,10 @@ cts_encr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
|
||||
struct iov_cursor cursor;
|
||||
AES_KEY enck;
|
||||
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
memset(iv_cts,0,sizeof(iv_cts));
|
||||
if (ivec && ivec->data){
|
||||
if (ivec->length != sizeof(iv_cts))
|
||||
@@ -190,6 +202,10 @@ cts_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
|
||||
struct iov_cursor cursor;
|
||||
AES_KEY deck;
|
||||
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
memset(iv_cts,0,sizeof(iv_cts));
|
||||
if (ivec && ivec->data){
|
||||
if (ivec->length != sizeof(iv_cts))
|
||||
diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
|
||||
index f79679a0b..7cc7fc6fb 100644
|
||||
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
|
||||
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
|
||||
@@ -92,6 +92,10 @@ cbc_enc(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
struct iov_cursor cursor;
|
||||
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
if (ctx == NULL)
|
||||
return ENOMEM;
|
||||
@@ -126,6 +130,10 @@ cbc_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
struct iov_cursor cursor;
|
||||
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
if (ctx == NULL)
|
||||
return ENOMEM;
|
||||
@@ -161,6 +169,10 @@ cts_encr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
|
||||
struct iov_cursor cursor;
|
||||
CAMELLIA_KEY enck;
|
||||
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
memset(iv_cts,0,sizeof(iv_cts));
|
||||
if (ivec && ivec->data){
|
||||
if (ivec->length != sizeof(iv_cts))
|
||||
@@ -214,6 +226,10 @@ cts_decr(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
|
||||
struct iov_cursor cursor;
|
||||
CAMELLIA_KEY deck;
|
||||
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
memset(iv_cts,0,sizeof(iv_cts));
|
||||
if (ivec && ivec->data){
|
||||
if (ivec->length != sizeof(iv_cts))
|
||||
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
|
||||
index 9bf407899..a10cb5192 100644
|
||||
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
|
||||
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
|
||||
@@ -66,6 +66,10 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
|
||||
EVP_CIPHER_CTX *ctx = NULL;
|
||||
struct arcfour_state *arcstate;
|
||||
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
if (FIPS_mode())
|
||||
return KRB5_CRYPTO_INTERNAL;
|
||||
|
||||
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
||||
index 2eb5139c0..09d7b3896 100644
|
||||
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
||||
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
||||
@@ -41,6 +41,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
|
||||
const krb5_data *d;
|
||||
size_t i;
|
||||
int ok;
|
||||
+ krb5_error_code ret;
|
||||
+
|
||||
+ ret = krb5int_crypto_init();
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
if (output->length != (unsigned int)EVP_MD_size(type))
|
||||
return KRB5_CRYPTO_INTERNAL;
|
||||
diff --git a/src/lib/crypto/openssl/init.c b/src/lib/crypto/openssl/init.c
|
||||
index 1139bce53..f72dbfe81 100644
|
||||
--- a/src/lib/crypto/openssl/init.c
|
||||
+++ b/src/lib/crypto/openssl/init.c
|
||||
@@ -26,12 +26,65 @@
|
||||
|
||||
#include "crypto_int.h"
|
||||
|
||||
+#ifdef HAVE_OSSL_PROVIDER_LOAD
|
||||
+
|
||||
+/*
|
||||
+ * Starting in OpenSSL 3, algorithms are grouped into containers called
|
||||
+ * "providers", not all of which are loaded by default. At time of writing,
|
||||
+ * we need MD4 and RC4 from the legacy provider. Oddly, 3DES is not in
|
||||
+ * legacy.
|
||||
+ */
|
||||
+
|
||||
+#include <openssl/provider.h>
|
||||
+
|
||||
+static OSSL_PROVIDER *legacy_provider = NULL;
|
||||
+static OSSL_PROVIDER *default_provider = NULL;
|
||||
+
|
||||
+static void
|
||||
+unload_providers(void)
|
||||
+{
|
||||
+ if (default_provider != NULL)
|
||||
+ (void)OSSL_PROVIDER_unload(default_provider);
|
||||
+ if (legacy_provider != NULL)
|
||||
+ (void)OSSL_PROVIDER_unload(legacy_provider);
|
||||
+ default_provider = NULL;
|
||||
+ legacy_provider = NULL;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+krb5int_crypto_impl_init(void)
|
||||
+{
|
||||
+ legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
|
||||
+ default_provider = OSSL_PROVIDER_load(NULL, "default");
|
||||
+
|
||||
+ /*
|
||||
+ * Someone might build openssl without the legacy provider. They will
|
||||
+ * have a bad time, but some things will still work. I don't know think
|
||||
+ * this configuration is worth supporting.
|
||||
+ */
|
||||
+ if (legacy_provider == NULL || default_provider == NULL)
|
||||
+ abort();
|
||||
+
|
||||
+ /*
|
||||
+ * If we attempt to do this with our normal LIBFINIFUNC logic (DT_FINI),
|
||||
+ * OpenSSL will have cleaned itself up by the time we're invoked. OpenSSL
|
||||
+ * registers its cleanup (OPENSSL_cleanup) with atexit() - do the same and
|
||||
+ * we'll be higher on the stack.
|
||||
+ */
|
||||
+ atexit(unload_providers);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#else /* !HAVE_OSSL_PROVIDER_LOAD */
|
||||
+
|
||||
int
|
||||
krb5int_crypto_impl_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#endif
|
||||
+
|
||||
void
|
||||
krb5int_crypto_impl_cleanup(void)
|
||||
{
|
||||
diff --git a/src/plugins/preauth/pkinit/Makefile.in b/src/plugins/preauth/pkinit/Makefile.in
|
||||
index 15ca0eb48..d20fb18a8 100644
|
||||
--- a/src/plugins/preauth/pkinit/Makefile.in
|
||||
+++ b/src/plugins/preauth/pkinit/Makefile.in
|
||||
@@ -5,6 +5,7 @@ MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR)
|
||||
LIBBASE=pkinit
|
||||
LIBMAJOR=0
|
||||
LIBMINOR=0
|
||||
+LIBINITFUNC=pkinit_openssl_init
|
||||
RELDIR=../plugins/preauth/pkinit
|
||||
# Depends on libk5crypto and libkrb5
|
||||
SHLIB_EXPDEPS = \
|
||||
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||
index 350c2118a..42e5c581d 100644
|
||||
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||
@@ -44,6 +44,13 @@
|
||||
#include <openssl/params.h>
|
||||
#endif
|
||||
|
||||
+#ifdef HAVE_OSSL_PROVIDER_LOAD
|
||||
+#include <openssl/provider.h>
|
||||
+
|
||||
+static OSSL_PROVIDER *legacy_provider = NULL;
|
||||
+static OSSL_PROVIDER *default_provider = NULL;
|
||||
+#endif
|
||||
+
|
||||
static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context );
|
||||
static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context );
|
||||
|
||||
@@ -2937,12 +2944,32 @@ cleanup:
|
||||
return retval;
|
||||
}
|
||||
|
||||
+/* pkinit_openssl_init() and unload_providers() are largely duplicated from
|
||||
+ * lib/crypto/openssl/init.c - see explanations there. */
|
||||
+static void
|
||||
+unload_providers(void)
|
||||
+{
|
||||
+ if (default_provider != NULL)
|
||||
+ (void)OSSL_PROVIDER_unload(default_provider);
|
||||
+ if (legacy_provider != NULL)
|
||||
+ (void)OSSL_PROVIDER_unload(legacy_provider);
|
||||
+ default_provider = NULL;
|
||||
+ legacy_provider = NULL;
|
||||
+}
|
||||
+
|
||||
int
|
||||
pkinit_openssl_init()
|
||||
{
|
||||
- /* Initialize OpenSSL. */
|
||||
- ERR_load_crypto_strings();
|
||||
- OpenSSL_add_all_algorithms();
|
||||
+#ifdef HAVE_OSSL_PROVIDER_LOAD
|
||||
+ legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
|
||||
+ default_provider = OSSL_PROVIDER_load(NULL, "default");
|
||||
+
|
||||
+ if (legacy_provider == NULL || default_provider == NULL)
|
||||
+ abort();
|
||||
+
|
||||
+ atexit(unload_providers);
|
||||
+#endif
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
27
SOURCES/Make-KCM-iteration-fallback-work-with-sssd-kcm.patch
Normal file
27
SOURCES/Make-KCM-iteration-fallback-work-with-sssd-kcm.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From 68a557557ab8a3208fab8a70daf4d970b9fc4787 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
|
||||
Date: Tue, 30 Mar 2021 14:35:28 +0200
|
||||
Subject: [PATCH] Make KCM iteration fallback work with sssd-kcm
|
||||
|
||||
sssd-kcm returns KRB5_CC_IO if the operation code is not known.
|
||||
|
||||
ticket: 8990
|
||||
(cherry picked from commit 06afae820a44c1dc96ad88a0b16c3e50bc938b2a)
|
||||
(cherry picked from commit 2dbca7e14c945d6394e0e05f285a068dcd541295)
|
||||
---
|
||||
src/lib/krb5/ccache/cc_kcm.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||
index 1f81a2190..46705f1da 100644
|
||||
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||
@@ -876,7 +876,7 @@ kcm_start_seq_get(krb5_context context, krb5_ccache cache,
|
||||
ret = kcmreq_get_cred_list(&req, &creds);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
- } else if (ret == KRB5_FCC_INTERNAL) {
|
||||
+ } else if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
|
||||
/* Fall back to GET_CRED_UUID_LIST. */
|
||||
kcmreq_free(&req);
|
||||
kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
|
1751
SOURCES/Move-some-dejagnu-kadmin-tests-to-Python-tests.patch
Normal file
1751
SOURCES/Move-some-dejagnu-kadmin-tests-to-Python-tests.patch
Normal file
File diff suppressed because it is too large
Load Diff
150
SOURCES/Remove-deprecated-OpenSSL-calls-from-softpkcs11.patch
Normal file
150
SOURCES/Remove-deprecated-OpenSSL-calls-from-softpkcs11.patch
Normal file
@ -0,0 +1,150 @@
|
||||
From c99ecf1bb49e2fbd0bf30a7b357cf06407b9588a Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Sat, 15 May 2021 18:04:58 -0400
|
||||
Subject: [PATCH] Remove deprecated OpenSSL calls from softpkcs11
|
||||
|
||||
Rewrite add_pubkey_info() in terms of the EVP_PKEY interface. In this
|
||||
process, fix its unchecked allocations and fail fast for non-RSA keys.
|
||||
|
||||
(cherry picked from commit d6bf42279675100e3e4fe7c6e08eef74d49624cb)
|
||||
(cherry picked from commit 5072bfdfaddae762680d0f9d97afa6dbf8274760)
|
||||
---
|
||||
src/configure.ac | 1 +
|
||||
src/tests/softpkcs11/main.c | 106 ++++++++++++++++++++++++------------
|
||||
2 files changed, 72 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/src/configure.ac b/src/configure.ac
|
||||
index 3e1052db7..eb6307468 100644
|
||||
--- a/src/configure.ac
|
||||
+++ b/src/configure.ac
|
||||
@@ -1114,6 +1114,7 @@ int i = 1;
|
||||
])], k5_cv_openssl_version_okay=yes, k5_cv_openssl_version_okay=no)])
|
||||
old_LIBS="$LIBS"
|
||||
AC_CHECK_LIB(crypto, PKCS7_get_signer_info)
|
||||
+ AC_CHECK_FUNCS(EVP_PKEY_get_bn_param)
|
||||
LIBS="$old_LIBS"
|
||||
fi
|
||||
if test "$k5_cv_openssl_version_okay" = yes && (test "$enable_pkinit" = yes || test "$enable_pkinit" = try); then
|
||||
diff --git a/src/tests/softpkcs11/main.c b/src/tests/softpkcs11/main.c
|
||||
index caa537b68..86b4ef711 100644
|
||||
--- a/src/tests/softpkcs11/main.c
|
||||
+++ b/src/tests/softpkcs11/main.c
|
||||
@@ -413,47 +413,83 @@ add_object_attribute(struct st_object *o,
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
+#ifdef HAVE_EVP_PKEY_GET_BN_PARAM
|
||||
+
|
||||
+/* Declare owner pointers since EVP_PKEY_get_bn_param() gives us copies. */
|
||||
+#define DECLARE_BIGNUM(name) BIGNUM *name = NULL
|
||||
+#define RELEASE_BIGNUM(bn) BN_clear_free(bn)
|
||||
static CK_RV
|
||||
-add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
|
||||
+get_bignums(EVP_PKEY *key, BIGNUM **n, BIGNUM **e)
|
||||
{
|
||||
- switch (key_type) {
|
||||
- case CKK_RSA: {
|
||||
- CK_BYTE *modulus = NULL;
|
||||
- size_t modulus_len = 0;
|
||||
- CK_ULONG modulus_bits = 0;
|
||||
- CK_BYTE *exponent = NULL;
|
||||
- size_t exponent_len = 0;
|
||||
- const RSA *rsa;
|
||||
- const BIGNUM *n, *e;
|
||||
+ if (EVP_PKEY_get_bn_param(key, "n", n) == 0 ||
|
||||
+ EVP_PKEY_get_bn_param(key, "e", e) == 0)
|
||||
+ return CKR_DEVICE_ERROR;
|
||||
|
||||
- rsa = EVP_PKEY_get0_RSA(key);
|
||||
- RSA_get0_key(rsa, &n, &e, NULL);
|
||||
- modulus_bits = BN_num_bits(n);
|
||||
-
|
||||
- modulus_len = BN_num_bytes(n);
|
||||
- modulus = malloc(modulus_len);
|
||||
- BN_bn2bin(n, modulus);
|
||||
-
|
||||
- exponent_len = BN_num_bytes(e);
|
||||
- exponent = malloc(exponent_len);
|
||||
- BN_bn2bin(e, exponent);
|
||||
-
|
||||
- add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
|
||||
- add_object_attribute(o, 0, CKA_MODULUS_BITS,
|
||||
- &modulus_bits, sizeof(modulus_bits));
|
||||
- add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
|
||||
- exponent, exponent_len);
|
||||
-
|
||||
- free(modulus);
|
||||
- free(exponent);
|
||||
- }
|
||||
- default:
|
||||
- /* XXX */
|
||||
- break;
|
||||
- }
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
+#else
|
||||
+
|
||||
+/* Declare const pointers since the old API gives us aliases. */
|
||||
+#define DECLARE_BIGNUM(name) const BIGNUM *name
|
||||
+#define RELEASE_BIGNUM(bn)
|
||||
+static CK_RV
|
||||
+get_bignums(EVP_PKEY *key, const BIGNUM **n, const BIGNUM **e)
|
||||
+{
|
||||
+ const RSA *rsa;
|
||||
+
|
||||
+ rsa = EVP_PKEY_get0_RSA(key);
|
||||
+ RSA_get0_key(rsa, n, e, NULL);
|
||||
+
|
||||
+ return CKR_OK;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+static CK_RV
|
||||
+add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
|
||||
+{
|
||||
+ CK_BYTE *modulus = NULL, *exponent = 0;
|
||||
+ size_t modulus_len = 0, exponent_len = 0;
|
||||
+ CK_ULONG modulus_bits = 0;
|
||||
+ CK_RV ret;
|
||||
+ DECLARE_BIGNUM(n);
|
||||
+ DECLARE_BIGNUM(e);
|
||||
+
|
||||
+ if (key_type != CKK_RSA)
|
||||
+ abort();
|
||||
+
|
||||
+ ret = get_bignums(key, &n, &e);
|
||||
+ if (ret != CKR_OK)
|
||||
+ goto done;
|
||||
+
|
||||
+ modulus_bits = BN_num_bits(n);
|
||||
+ modulus_len = BN_num_bytes(n);
|
||||
+ exponent_len = BN_num_bytes(e);
|
||||
+
|
||||
+ modulus = malloc(modulus_len);
|
||||
+ exponent = malloc(exponent_len);
|
||||
+ if (modulus == NULL || exponent == NULL) {
|
||||
+ ret = CKR_DEVICE_MEMORY;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ BN_bn2bin(n, modulus);
|
||||
+ BN_bn2bin(e, exponent);
|
||||
+
|
||||
+ add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
|
||||
+ add_object_attribute(o, 0, CKA_MODULUS_BITS, &modulus_bits,
|
||||
+ sizeof(modulus_bits));
|
||||
+ add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT, exponent, exponent_len);
|
||||
+
|
||||
+ ret = CKR_OK;
|
||||
+done:
|
||||
+ free(modulus);
|
||||
+ free(exponent);
|
||||
+ RELEASE_BIGNUM(n);
|
||||
+ RELEASE_BIGNUM(e);
|
||||
+ return ret;
|
||||
+}
|
||||
|
||||
static int
|
||||
pem_callback(char *buf, int num, int w, void *key)
|
578
SOURCES/Support-host-based-GSS-initiator-names.patch
Normal file
578
SOURCES/Support-host-based-GSS-initiator-names.patch
Normal file
@ -0,0 +1,578 @@
|
||||
From e33835c4b6c6ce71757e9f659db03afa4bfd9a9a Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Fri, 15 Jan 2021 13:51:34 -0500
|
||||
Subject: [PATCH] Support host-based GSS initiator names
|
||||
|
||||
When checking if we can get initial credentials in the GSS krb5 mech,
|
||||
use krb5_kt_have_match() to support fallback iteration. When scanning
|
||||
the ccache or getting initial credentials, rewrite cred->name->princ
|
||||
to the canonical client name. When a name check is necessary (such as
|
||||
when the caller specifies both a name and ccache), use a new internal
|
||||
API k5_sname_compare() to support fallback iteration. Add fallback
|
||||
iteration to krb5_cc_cache_match() to allow host-based names to be
|
||||
canonicalized against the cache collection.
|
||||
|
||||
Create and store the matching principal for acceptor names in
|
||||
acquire_accept_cred() so that it isn't affected by changes in
|
||||
cred->name->princ during acquire_init_cred().
|
||||
|
||||
ticket: 8978 (new)
|
||||
(cherry picked from commit c374ab40dd059a5938ffc0440d87457ac5da3a46)
|
||||
---
|
||||
src/include/k5-int.h | 9 +++
|
||||
src/include/k5-trace.h | 3 +
|
||||
src/lib/gssapi/krb5/accept_sec_context.c | 15 +---
|
||||
src/lib/gssapi/krb5/acquire_cred.c | 89 ++++++++++++++----------
|
||||
src/lib/gssapi/krb5/gssapiP_krb5.h | 1 +
|
||||
src/lib/gssapi/krb5/rel_cred.c | 1 +
|
||||
src/lib/krb5/ccache/cccursor.c | 57 +++++++++++----
|
||||
src/lib/krb5/libkrb5.exports | 1 +
|
||||
src/lib/krb5/os/sn2princ.c | 23 +++++-
|
||||
src/lib/krb5_32.def | 1 +
|
||||
src/tests/gssapi/t_client_keytab.py | 44 ++++++++++++
|
||||
src/tests/gssapi/t_credstore.py | 32 +++++++++
|
||||
12 files changed, 214 insertions(+), 62 deletions(-)
|
||||
|
||||
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
|
||||
index efb523689..46f2ce2d3 100644
|
||||
--- a/src/include/k5-int.h
|
||||
+++ b/src/include/k5-int.h
|
||||
@@ -2411,4 +2411,13 @@ void k5_change_error_message_code(krb5_context ctx, krb5_error_code oldcode,
|
||||
#define k5_prependmsg krb5_prepend_error_message
|
||||
#define k5_wrapmsg krb5_wrap_error_message
|
||||
|
||||
+/*
|
||||
+ * Like krb5_principal_compare(), but with canonicalization of sname if
|
||||
+ * fallback is enabled. This function should be avoided if multiple matches
|
||||
+ * are required, since repeated canonicalization is inefficient.
|
||||
+ */
|
||||
+krb5_boolean
|
||||
+k5_sname_compare(krb5_context context, krb5_const_principal sname,
|
||||
+ krb5_const_principal princ);
|
||||
+
|
||||
#endif /* _KRB5_INT_H */
|
||||
diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
|
||||
index b3e039dc8..79b5a7a85 100644
|
||||
--- a/src/include/k5-trace.h
|
||||
+++ b/src/include/k5-trace.h
|
||||
@@ -105,6 +105,9 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
|
||||
|
||||
#endif /* DISABLE_TRACING */
|
||||
|
||||
+#define TRACE_CC_CACHE_MATCH(c, princ, ret) \
|
||||
+ TRACE(c, "Matching {princ} in collection with result: {kerr}", \
|
||||
+ princ, ret)
|
||||
#define TRACE_CC_DESTROY(c, cache) \
|
||||
TRACE(c, "Destroying ccache {ccache}", cache)
|
||||
#define TRACE_CC_GEN_NEW(c, cache) \
|
||||
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||
index fcf2c2152..a1d7e0d96 100644
|
||||
--- a/src/lib/gssapi/krb5/accept_sec_context.c
|
||||
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||
@@ -683,7 +683,6 @@ kg_accept_krb5(minor_status, context_handle,
|
||||
krb5_flags ap_req_options = 0;
|
||||
krb5_enctype negotiated_etype;
|
||||
krb5_authdata_context ad_context = NULL;
|
||||
- krb5_principal accprinc = NULL;
|
||||
krb5_ap_req *request = NULL;
|
||||
|
||||
code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
|
||||
@@ -849,17 +848,9 @@ kg_accept_krb5(minor_status, context_handle,
|
||||
}
|
||||
}
|
||||
|
||||
- if (!cred->default_identity) {
|
||||
- if ((code = kg_acceptor_princ(context, cred->name, &accprinc))) {
|
||||
- major_status = GSS_S_FAILURE;
|
||||
- goto fail;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- code = krb5_rd_req_decoded(context, &auth_context, request, accprinc,
|
||||
- cred->keytab, &ap_req_options, NULL);
|
||||
-
|
||||
- krb5_free_principal(context, accprinc);
|
||||
+ code = krb5_rd_req_decoded(context, &auth_context, request,
|
||||
+ cred->acceptor_mprinc, cred->keytab,
|
||||
+ &ap_req_options, NULL);
|
||||
if (code) {
|
||||
major_status = GSS_S_FAILURE;
|
||||
goto fail;
|
||||
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
|
||||
index 632ee7def..e226a0269 100644
|
||||
--- a/src/lib/gssapi/krb5/acquire_cred.c
|
||||
+++ b/src/lib/gssapi/krb5/acquire_cred.c
|
||||
@@ -123,11 +123,11 @@ gss_krb5int_register_acceptor_identity(OM_uint32 *minor_status,
|
||||
/* Try to verify that keytab contains at least one entry for name. Return 0 if
|
||||
* it does, KRB5_KT_NOTFOUND if it doesn't, or another error as appropriate. */
|
||||
static krb5_error_code
|
||||
-check_keytab(krb5_context context, krb5_keytab kt, krb5_gss_name_t name)
|
||||
+check_keytab(krb5_context context, krb5_keytab kt, krb5_gss_name_t name,
|
||||
+ krb5_principal mprinc)
|
||||
{
|
||||
krb5_error_code code;
|
||||
krb5_keytab_entry ent;
|
||||
- krb5_principal accprinc = NULL;
|
||||
char *princname;
|
||||
|
||||
if (name->service == NULL) {
|
||||
@@ -141,21 +141,15 @@ check_keytab(krb5_context context, krb5_keytab kt, krb5_gss_name_t name)
|
||||
if (kt->ops->start_seq_get == NULL)
|
||||
return 0;
|
||||
|
||||
- /* Get the partial principal for the acceptor name. */
|
||||
- code = kg_acceptor_princ(context, name, &accprinc);
|
||||
- if (code)
|
||||
- return code;
|
||||
-
|
||||
- /* Scan the keytab for host-based entries matching accprinc. */
|
||||
- code = k5_kt_have_match(context, kt, accprinc);
|
||||
+ /* Scan the keytab for host-based entries matching mprinc. */
|
||||
+ code = k5_kt_have_match(context, kt, mprinc);
|
||||
if (code == KRB5_KT_NOTFOUND) {
|
||||
- if (krb5_unparse_name(context, accprinc, &princname) == 0) {
|
||||
+ if (krb5_unparse_name(context, mprinc, &princname) == 0) {
|
||||
k5_setmsg(context, code, _("No key table entry found matching %s"),
|
||||
princname);
|
||||
free(princname);
|
||||
}
|
||||
}
|
||||
- krb5_free_principal(context, accprinc);
|
||||
return code;
|
||||
}
|
||||
|
||||
@@ -202,8 +196,14 @@ acquire_accept_cred(krb5_context context, OM_uint32 *minor_status,
|
||||
}
|
||||
|
||||
if (cred->name != NULL) {
|
||||
+ code = kg_acceptor_princ(context, cred->name, &cred->acceptor_mprinc);
|
||||
+ if (code) {
|
||||
+ major = GSS_S_FAILURE;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
/* Make sure we have keys matching the desired name in the keytab. */
|
||||
- code = check_keytab(context, kt, cred->name);
|
||||
+ code = check_keytab(context, kt, cred->name, cred->acceptor_mprinc);
|
||||
if (code) {
|
||||
if (code == KRB5_KT_NOTFOUND) {
|
||||
k5_change_error_message_code(context, code, KG_KEYTAB_NOMATCH);
|
||||
@@ -324,7 +324,6 @@ static krb5_boolean
|
||||
can_get_initial_creds(krb5_context context, krb5_gss_cred_id_rec *cred)
|
||||
{
|
||||
krb5_error_code code;
|
||||
- krb5_keytab_entry entry;
|
||||
|
||||
if (cred->password != NULL)
|
||||
return TRUE;
|
||||
@@ -336,20 +335,21 @@ can_get_initial_creds(krb5_context context, krb5_gss_cred_id_rec *cred)
|
||||
if (cred->name == NULL)
|
||||
return !krb5_kt_have_content(context, cred->client_keytab);
|
||||
|
||||
- /* Check if we have a keytab key for the client principal. */
|
||||
- code = krb5_kt_get_entry(context, cred->client_keytab, cred->name->princ,
|
||||
- 0, 0, &entry);
|
||||
- if (code) {
|
||||
- krb5_clear_error_message(context);
|
||||
- return FALSE;
|
||||
- }
|
||||
- krb5_free_keytab_entry_contents(context, &entry);
|
||||
- return TRUE;
|
||||
+ /*
|
||||
+ * Check if we have a keytab key for the client principal. This is a bit
|
||||
+ * more permissive than we really want because krb5_kt_have_match()
|
||||
+ * supports wildcarding and obeys ignore_acceptor_hostname, but that should
|
||||
+ * generally be harmless.
|
||||
+ */
|
||||
+ code = k5_kt_have_match(context, cred->client_keytab, cred->name->princ);
|
||||
+ return code == 0;
|
||||
}
|
||||
|
||||
-/* Scan cred->ccache for name, expiry time, impersonator, refresh time. */
|
||||
+/* Scan cred->ccache for name, expiry time, impersonator, refresh time. If
|
||||
+ * check_name is true, verify the cache name against the credential name. */
|
||||
static krb5_error_code
|
||||
-scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred)
|
||||
+scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred,
|
||||
+ krb5_boolean check_name)
|
||||
{
|
||||
krb5_error_code code;
|
||||
krb5_ccache ccache = cred->ccache;
|
||||
@@ -365,23 +365,31 @@ scan_ccache(krb5_context context, krb5_gss_cred_id_rec *cred)
|
||||
if (code)
|
||||
return code;
|
||||
|
||||
- /* Credentials cache principal must match the initiator name. */
|
||||
code = krb5_cc_get_principal(context, ccache, &ccache_princ);
|
||||
if (code != 0)
|
||||
goto cleanup;
|
||||
- if (cred->name != NULL &&
|
||||
- !krb5_principal_compare(context, ccache_princ, cred->name->princ)) {
|
||||
- code = KG_CCACHE_NOMATCH;
|
||||
- goto cleanup;
|
||||
- }
|
||||
|
||||
- /* Save the ccache principal as the credential name if not already set. */
|
||||
- if (!cred->name) {
|
||||
+ if (cred->name == NULL) {
|
||||
+ /* Save the ccache principal as the credential name. */
|
||||
code = kg_init_name(context, ccache_princ, NULL, NULL, NULL,
|
||||
KG_INIT_NAME_NO_COPY, &cred->name);
|
||||
if (code)
|
||||
goto cleanup;
|
||||
ccache_princ = NULL;
|
||||
+ } else {
|
||||
+ /* Check against the desired name if needed. */
|
||||
+ if (check_name) {
|
||||
+ if (!k5_sname_compare(context, cred->name->princ, ccache_princ)) {
|
||||
+ code = KG_CCACHE_NOMATCH;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Replace the credential name principal with the canonical client
|
||||
+ * principal, retaining acceptor_mprinc if set. */
|
||||
+ krb5_free_principal(context, cred->name->princ);
|
||||
+ cred->name->princ = ccache_princ;
|
||||
+ ccache_princ = NULL;
|
||||
}
|
||||
|
||||
assert(cred->name->princ != NULL);
|
||||
@@ -447,7 +455,7 @@ get_cache_for_name(krb5_context context, krb5_gss_cred_id_rec *cred)
|
||||
assert(cred->name != NULL && cred->ccache == NULL);
|
||||
#ifdef USE_LEASH
|
||||
code = get_ccache_leash(context, cred->name->princ, &cred->ccache);
|
||||
- return code ? code : scan_ccache(context, cred);
|
||||
+ return code ? code : scan_ccache(context, cred, TRUE);
|
||||
#else
|
||||
/* Check first whether we can acquire tickets, to avoid overwriting the
|
||||
* extended error message from krb5_cc_cache_match. */
|
||||
@@ -456,7 +464,7 @@ get_cache_for_name(krb5_context context, krb5_gss_cred_id_rec *cred)
|
||||
/* Look for an existing cache for the client principal. */
|
||||
code = krb5_cc_cache_match(context, cred->name->princ, &cred->ccache);
|
||||
if (code == 0)
|
||||
- return scan_ccache(context, cred);
|
||||
+ return scan_ccache(context, cred, FALSE);
|
||||
if (code != KRB5_CC_NOTFOUND || !can_get)
|
||||
return code;
|
||||
krb5_clear_error_message(context);
|
||||
@@ -633,6 +641,13 @@ get_initial_cred(krb5_context context, const struct verify_params *verify,
|
||||
kg_cred_set_initial_refresh(context, cred, &creds.times);
|
||||
cred->have_tgt = TRUE;
|
||||
cred->expire = creds.times.endtime;
|
||||
+
|
||||
+ /* Steal the canonical client principal name from creds and save it in the
|
||||
+ * credential name, retaining acceptor_mprinc if set. */
|
||||
+ krb5_free_principal(context, cred->name->princ);
|
||||
+ cred->name->princ = creds.client;
|
||||
+ creds.client = NULL;
|
||||
+
|
||||
krb5_free_cred_contents(context, &creds);
|
||||
cleanup:
|
||||
krb5_get_init_creds_opt_free(context, opt);
|
||||
@@ -721,7 +736,7 @@ acquire_init_cred(krb5_context context, OM_uint32 *minor_status,
|
||||
|
||||
if (cred->ccache != NULL) {
|
||||
/* The caller specified a ccache; check what's in it. */
|
||||
- code = scan_ccache(context, cred);
|
||||
+ code = scan_ccache(context, cred, TRUE);
|
||||
if (code == KRB5_FCC_NOFILE) {
|
||||
/* See if we can get initial creds. If the caller didn't specify
|
||||
* a name, pick one from the client keytab. */
|
||||
@@ -984,7 +999,7 @@ kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
|
||||
}
|
||||
}
|
||||
if (cred->ccache != NULL) {
|
||||
- code = scan_ccache(context, cred);
|
||||
+ code = scan_ccache(context, cred, FALSE);
|
||||
if (code)
|
||||
goto kerr;
|
||||
}
|
||||
@@ -996,7 +1011,7 @@ kg_cred_resolve(OM_uint32 *minor_status, krb5_context context,
|
||||
code = krb5int_cc_default(context, &cred->ccache);
|
||||
if (code)
|
||||
goto kerr;
|
||||
- code = scan_ccache(context, cred);
|
||||
+ code = scan_ccache(context, cred, FALSE);
|
||||
if (code == KRB5_FCC_NOFILE) {
|
||||
/* Default ccache doesn't exist; fall through to client keytab. */
|
||||
krb5_cc_close(context, cred->ccache);
|
||||
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
|
||||
index 3bacdcd35..fd7abbd77 100644
|
||||
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
|
||||
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
|
||||
@@ -175,6 +175,7 @@ typedef struct _krb5_gss_cred_id_rec {
|
||||
/* name/type of credential */
|
||||
gss_cred_usage_t usage;
|
||||
krb5_gss_name_t name;
|
||||
+ krb5_principal acceptor_mprinc;
|
||||
krb5_principal impersonator;
|
||||
unsigned int default_identity : 1;
|
||||
unsigned int iakerb_mech : 1;
|
||||
diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c
|
||||
index a9515daf7..0da6c1b95 100644
|
||||
--- a/src/lib/gssapi/krb5/rel_cred.c
|
||||
+++ b/src/lib/gssapi/krb5/rel_cred.c
|
||||
@@ -72,6 +72,7 @@ krb5_gss_release_cred(minor_status, cred_handle)
|
||||
if (cred->name)
|
||||
kg_release_name(context, &cred->name);
|
||||
|
||||
+ krb5_free_principal(context, cred->acceptor_mprinc);
|
||||
krb5_free_principal(context, cred->impersonator);
|
||||
|
||||
if (cred->req_enctypes)
|
||||
diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c
|
||||
index 8f5872116..760216d05 100644
|
||||
--- a/src/lib/krb5/ccache/cccursor.c
|
||||
+++ b/src/lib/krb5/ccache/cccursor.c
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "cc-int.h"
|
||||
#include "../krb/int-proto.h"
|
||||
+#include "../os/os-proto.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -141,18 +142,18 @@ krb5_cccol_cursor_free(krb5_context context,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-krb5_error_code KRB5_CALLCONV
|
||||
-krb5_cc_cache_match(krb5_context context, krb5_principal client,
|
||||
- krb5_ccache *cache_out)
|
||||
+static krb5_error_code
|
||||
+match_caches(krb5_context context, krb5_const_principal client,
|
||||
+ krb5_ccache *cache_out)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_cccol_cursor cursor;
|
||||
krb5_ccache cache = NULL;
|
||||
krb5_principal princ;
|
||||
- char *name;
|
||||
krb5_boolean eq;
|
||||
|
||||
*cache_out = NULL;
|
||||
+
|
||||
ret = krb5_cccol_cursor_new(context, &cursor);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -169,20 +170,52 @@ krb5_cc_cache_match(krb5_context context, krb5_principal client,
|
||||
krb5_cc_close(context, cache);
|
||||
}
|
||||
krb5_cccol_cursor_free(context, &cursor);
|
||||
+
|
||||
if (ret)
|
||||
return ret;
|
||||
- if (cache == NULL) {
|
||||
- ret = krb5_unparse_name(context, client, &name);
|
||||
- if (ret == 0) {
|
||||
- k5_setmsg(context, KRB5_CC_NOTFOUND,
|
||||
+ if (cache == NULL)
|
||||
+ return KRB5_CC_NOTFOUND;
|
||||
+
|
||||
+ *cache_out = cache;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+krb5_error_code KRB5_CALLCONV
|
||||
+krb5_cc_cache_match(krb5_context context, krb5_principal client,
|
||||
+ krb5_ccache *cache_out)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ struct canonprinc iter = { client, .subst_defrealm = TRUE };
|
||||
+ krb5_const_principal canonprinc = NULL;
|
||||
+ krb5_ccache cache = NULL;
|
||||
+ char *name;
|
||||
+
|
||||
+ *cache_out = NULL;
|
||||
+
|
||||
+ while ((ret = k5_canonprinc(context, &iter, &canonprinc)) == 0 &&
|
||||
+ canonprinc != NULL) {
|
||||
+ ret = match_caches(context, canonprinc, &cache);
|
||||
+ if (ret != KRB5_CC_NOTFOUND)
|
||||
+ break;
|
||||
+ }
|
||||
+ free_canonprinc(&iter);
|
||||
+
|
||||
+ if (ret == 0 && canonprinc == NULL) {
|
||||
+ ret = KRB5_CC_NOTFOUND;
|
||||
+ if (krb5_unparse_name(context, client, &name) == 0) {
|
||||
+ k5_setmsg(context, ret,
|
||||
_("Can't find client principal %s in cache collection"),
|
||||
name);
|
||||
krb5_free_unparsed_name(context, name);
|
||||
}
|
||||
- ret = KRB5_CC_NOTFOUND;
|
||||
- } else
|
||||
- *cache_out = cache;
|
||||
- return ret;
|
||||
+ }
|
||||
+
|
||||
+ TRACE_CC_CACHE_MATCH(context, client, ret);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ *cache_out = cache;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* Store the error state for code from context into errsave, but only if code
|
||||
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
|
||||
index adbfa332b..df6e2ffbe 100644
|
||||
--- a/src/lib/krb5/libkrb5.exports
|
||||
+++ b/src/lib/krb5/libkrb5.exports
|
||||
@@ -181,6 +181,7 @@ k5_size_authdata_context
|
||||
k5_size_context
|
||||
k5_size_keyblock
|
||||
k5_size_principal
|
||||
+k5_sname_compare
|
||||
k5_unmarshal_cred
|
||||
k5_unmarshal_princ
|
||||
k5_unwrap_cammac_svc
|
||||
diff --git a/src/lib/krb5/os/sn2princ.c b/src/lib/krb5/os/sn2princ.c
|
||||
index 8b7214189..c99b7da17 100644
|
||||
--- a/src/lib/krb5/os/sn2princ.c
|
||||
+++ b/src/lib/krb5/os/sn2princ.c
|
||||
@@ -277,7 +277,8 @@ k5_canonprinc(krb5_context context, struct canonprinc *iter,
|
||||
|
||||
/* If we're not doing fallback, the input principal is canonical. */
|
||||
if (context->dns_canonicalize_hostname != CANONHOST_FALLBACK ||
|
||||
- iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2) {
|
||||
+ iter->princ->type != KRB5_NT_SRV_HST || iter->princ->length != 2 ||
|
||||
+ iter->princ->data[1].length == 0) {
|
||||
*princ_out = (step == 1) ? iter->princ : NULL;
|
||||
return 0;
|
||||
}
|
||||
@@ -288,6 +289,26 @@ k5_canonprinc(krb5_context context, struct canonprinc *iter,
|
||||
return canonicalize_princ(context, iter, step == 2, princ_out);
|
||||
}
|
||||
|
||||
+krb5_boolean
|
||||
+k5_sname_compare(krb5_context context, krb5_const_principal sname,
|
||||
+ krb5_const_principal princ)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ struct canonprinc iter = { sname, .subst_defrealm = TRUE };
|
||||
+ krb5_const_principal canonprinc = NULL;
|
||||
+ krb5_boolean match = FALSE;
|
||||
+
|
||||
+ while ((ret = k5_canonprinc(context, &iter, &canonprinc)) == 0 &&
|
||||
+ canonprinc != NULL) {
|
||||
+ if (krb5_principal_compare(context, canonprinc, princ)) {
|
||||
+ match = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ free_canonprinc(&iter);
|
||||
+ return match;
|
||||
+}
|
||||
+
|
||||
krb5_error_code KRB5_CALLCONV
|
||||
krb5_sname_to_principal(krb5_context context, const char *hostname,
|
||||
const char *sname, krb5_int32 type,
|
||||
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
|
||||
index 60b8dd311..cf690dbe4 100644
|
||||
--- a/src/lib/krb5_32.def
|
||||
+++ b/src/lib/krb5_32.def
|
||||
@@ -507,3 +507,4 @@ EXPORTS
|
||||
; new in 1.20
|
||||
krb5_marshal_credentials @472
|
||||
krb5_unmarshal_credentials @473
|
||||
+ k5_sname_compare @474 ; PRIVATE GSSAPI
|
||||
diff --git a/src/tests/gssapi/t_client_keytab.py b/src/tests/gssapi/t_client_keytab.py
|
||||
index 7847b3ecd..9a61d53b8 100755
|
||||
--- a/src/tests/gssapi/t_client_keytab.py
|
||||
+++ b/src/tests/gssapi/t_client_keytab.py
|
||||
@@ -141,5 +141,49 @@ msgs = ('Getting initial credentials for user/admin@KRBTEST.COM',
|
||||
'/Matching credential not found')
|
||||
realm.run(['./t_ccselect', phost], expected_code=1,
|
||||
expected_msg='Ticket expired', expected_trace=msgs)
|
||||
+realm.run([kdestroy, '-A'])
|
||||
+
|
||||
+# Test 19: host-based initiator name
|
||||
+mark('host-based initiator name')
|
||||
+hsvc = 'h:svc@' + hostname
|
||||
+svcprinc = 'svc/%s@%s' % (hostname, realm.realm)
|
||||
+realm.addprinc(svcprinc)
|
||||
+realm.extract_keytab(svcprinc, realm.client_keytab)
|
||||
+# On the first run we match against the keytab while getting tickets,
|
||||
+# substituting the default realm.
|
||||
+msgs = ('/Can\'t find client principal svc/%s@ in' % hostname,
|
||||
+ 'Getting initial credentials for svc/%s@' % hostname,
|
||||
+ 'Found entries for %s in keytab' % svcprinc,
|
||||
+ 'Retrieving %s from FILE:%s' % (svcprinc, realm.client_keytab),
|
||||
+ 'Storing %s -> %s in' % (svcprinc, realm.krbtgt_princ),
|
||||
+ 'Retrieving %s -> %s from' % (svcprinc, realm.krbtgt_princ),
|
||||
+ 'authenticator for %s -> %s' % (svcprinc, realm.host_princ))
|
||||
+realm.run(['./t_ccselect', phost, hsvc], expected_trace=msgs)
|
||||
+# On the second run we match against the collection.
|
||||
+msgs = ('Matching svc/%s@ in collection with result: 0' % hostname,
|
||||
+ 'Getting credentials %s -> %s' % (svcprinc, realm.host_princ),
|
||||
+ 'authenticator for %s -> %s' % (svcprinc, realm.host_princ))
|
||||
+realm.run(['./t_ccselect', phost, hsvc], expected_trace=msgs)
|
||||
+realm.run([kdestroy, '-A'])
|
||||
+
|
||||
+# Test 20: host-based initiator name with fallback
|
||||
+mark('host-based fallback initiator name')
|
||||
+canonname = canonicalize_hostname(hostname)
|
||||
+if canonname != hostname:
|
||||
+ hfsvc = 'h:fsvc@' + hostname
|
||||
+ canonprinc = 'fsvc/%s@%s' % (canonname, realm.realm)
|
||||
+ realm.addprinc(canonprinc)
|
||||
+ realm.extract_keytab(canonprinc, realm.client_keytab)
|
||||
+ msgs = ('/Can\'t find client principal fsvc/%s@ in' % hostname,
|
||||
+ 'Found entries for %s in keytab' % canonprinc,
|
||||
+ 'authenticator for %s -> %s' % (canonprinc, realm.host_princ))
|
||||
+ realm.run(['./t_ccselect', phost, hfsvc], expected_trace=msgs)
|
||||
+ msgs = ('Matching fsvc/%s@ in collection with result: 0' % hostname,
|
||||
+ 'Getting credentials %s -> %s' % (canonprinc, realm.host_princ))
|
||||
+ realm.run(['./t_ccselect', phost, hfsvc], expected_trace=msgs)
|
||||
+ realm.run([kdestroy, '-A'])
|
||||
+else:
|
||||
+ skipped('GSS initiator name fallback test',
|
||||
+ '%s does not canonicalize to a different name' % hostname)
|
||||
|
||||
success('Client keytab tests')
|
||||
diff --git a/src/tests/gssapi/t_credstore.py b/src/tests/gssapi/t_credstore.py
|
||||
index c11975bf5..9be57bb82 100644
|
||||
--- a/src/tests/gssapi/t_credstore.py
|
||||
+++ b/src/tests/gssapi/t_credstore.py
|
||||
@@ -15,6 +15,38 @@ msgs = ('Storing %s -> %s in %s' % (service_cs, realm.krbtgt_princ,
|
||||
realm.run(['./t_credstore', '-s', 'p:' + service_cs, 'ccache', storagecache,
|
||||
'keytab', servicekeytab], expected_trace=msgs)
|
||||
|
||||
+mark('matching')
|
||||
+scc = 'FILE:' + os.path.join(realm.testdir, 'service_cache')
|
||||
+realm.kinit(realm.host_princ, flags=['-k', '-c', scc])
|
||||
+realm.run(['./t_credstore', '-i', 'p:' + realm.host_princ, 'ccache', scc])
|
||||
+realm.run(['./t_credstore', '-i', 'h:host', 'ccache', scc])
|
||||
+realm.run(['./t_credstore', '-i', 'h:host@' + hostname, 'ccache', scc])
|
||||
+realm.run(['./t_credstore', '-i', 'p:wrong', 'ccache', scc],
|
||||
+ expected_code=1, expected_msg='does not match desired name')
|
||||
+realm.run(['./t_credstore', '-i', 'h:host@-nomatch-', 'ccache', scc],
|
||||
+ expected_code=1, expected_msg='does not match desired name')
|
||||
+realm.run(['./t_credstore', '-i', 'h:svc', 'ccache', scc],
|
||||
+ expected_code=1, expected_msg='does not match desired name')
|
||||
+
|
||||
+mark('matching (fallback)')
|
||||
+canonname = canonicalize_hostname(hostname)
|
||||
+if canonname != hostname:
|
||||
+ canonprinc = 'host/%s@%s' % (canonname, realm.realm)
|
||||
+ realm.addprinc(canonprinc)
|
||||
+ realm.extract_keytab(canonprinc, realm.keytab)
|
||||
+ realm.kinit(canonprinc, flags=['-k', '-c', scc])
|
||||
+ realm.run(['./t_credstore', '-i', 'h:host', 'ccache', scc])
|
||||
+ realm.run(['./t_credstore', '-i', 'h:host@' + hostname, 'ccache', scc])
|
||||
+ realm.run(['./t_credstore', '-i', 'h:host@' + canonname, 'ccache', scc])
|
||||
+ realm.run(['./t_credstore', '-i', 'p:' + canonprinc, 'ccache', scc])
|
||||
+ realm.run(['./t_credstore', '-i', 'p:' + realm.host_princ, 'ccache', scc],
|
||||
+ expected_code=1, expected_msg='does not match desired name')
|
||||
+ realm.run(['./t_credstore', '-i', 'h:host@-nomatch-', 'ccache', scc],
|
||||
+ expected_code=1, expected_msg='does not match desired name')
|
||||
+else:
|
||||
+ skipped('fallback matching test',
|
||||
+ '%s does not canonicalize to a different name' % hostname)
|
||||
+
|
||||
mark('rcache')
|
||||
# t_credstore -r should produce a replay error normally, but not with
|
||||
# rcache set to "none:".
|
236
SOURCES/Use-KCM_OP_RETRIEVE-in-KCM-client.patch
Normal file
236
SOURCES/Use-KCM_OP_RETRIEVE-in-KCM-client.patch
Normal file
@ -0,0 +1,236 @@
|
||||
From 43e3bca2a711de257091454bc5e25a985340d847 Mon Sep 17 00:00:00 2001
|
||||
From: Greg Hudson <ghudson@mit.edu>
|
||||
Date: Fri, 26 Mar 2021 23:38:54 -0400
|
||||
Subject: [PATCH] Use KCM_OP_RETRIEVE in KCM client
|
||||
|
||||
In kcm_retrieve(), try KCM_OP_RETRIEVE. Fall back to iteration if the
|
||||
server doesn't implement it, or if we can an answer incompatible with
|
||||
KRB5_TC_SUPPORTED_KTYPES.
|
||||
|
||||
In kcmserver.py, implement partial decoding for creds and cred tags so
|
||||
that we can do a basic principal name match.
|
||||
|
||||
ticket: 8997 (new)
|
||||
(cherry picked from commit 795ebba8c039be172ab93cd41105c73ffdba0fdb)
|
||||
(cherry picked from commit c56d4b87de0f30a38dc61d374ad225d02d581eb3)
|
||||
---
|
||||
src/include/kcm.h | 2 +-
|
||||
src/lib/krb5/ccache/cc_kcm.c | 52 +++++++++++++++++++++++++++++++++---
|
||||
src/tests/kcmserver.py | 44 +++++++++++++++++++++++++++---
|
||||
src/tests/t_ccache.py | 11 +++++---
|
||||
4 files changed, 99 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/include/kcm.h b/src/include/kcm.h
|
||||
index 9b66f1cbd..85c20d345 100644
|
||||
--- a/src/include/kcm.h
|
||||
+++ b/src/include/kcm.h
|
||||
@@ -87,7 +87,7 @@ typedef enum kcm_opcode {
|
||||
KCM_OP_INITIALIZE, /* (name, princ) -> () */
|
||||
KCM_OP_DESTROY, /* (name) -> () */
|
||||
KCM_OP_STORE, /* (name, cred) -> () */
|
||||
- KCM_OP_RETRIEVE,
|
||||
+ KCM_OP_RETRIEVE, /* (name, flags, credtag) -> (cred) */
|
||||
KCM_OP_GET_PRINCIPAL, /* (name) -> (princ) */
|
||||
KCM_OP_GET_CRED_UUID_LIST, /* (name) -> (uuid, ...) */
|
||||
KCM_OP_GET_CRED_BY_UUID, /* (name, uuid) -> (cred) */
|
||||
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||
index 46705f1da..23fcf13ea 100644
|
||||
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||
@@ -826,9 +826,55 @@ static krb5_error_code KRB5_CALLCONV
|
||||
kcm_retrieve(krb5_context context, krb5_ccache cache, krb5_flags flags,
|
||||
krb5_creds *mcred, krb5_creds *cred_out)
|
||||
{
|
||||
- /* There is a KCM opcode for retrieving creds, but Heimdal's client doesn't
|
||||
- * use it. It causes the KCM daemon to actually make a TGS request. */
|
||||
- return k5_cc_retrieve_cred_default(context, cache, flags, mcred, cred_out);
|
||||
+ krb5_error_code ret;
|
||||
+ struct kcmreq req = EMPTY_KCMREQ;
|
||||
+ krb5_creds cred;
|
||||
+ krb5_enctype *enctypes = NULL;
|
||||
+
|
||||
+ memset(&cred, 0, sizeof(cred));
|
||||
+
|
||||
+ /* Include KCM_GC_CACHED in flags to prevent Heimdal's sssd from making a
|
||||
+ * TGS request itself. */
|
||||
+ kcmreq_init(&req, KCM_OP_RETRIEVE, cache);
|
||||
+ k5_buf_add_uint32_be(&req.reqbuf, map_tcflags(flags) | KCM_GC_CACHED);
|
||||
+ k5_marshal_mcred(&req.reqbuf, mcred);
|
||||
+ ret = cache_call(context, cache, &req);
|
||||
+
|
||||
+ /* Fall back to iteration if the server does not support retrieval. */
|
||||
+ if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
|
||||
+ ret = k5_cc_retrieve_cred_default(context, cache, flags, mcred,
|
||||
+ cred_out);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ ret = k5_unmarshal_cred(req.reply.ptr, req.reply.len, 4, &cred);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ /* In rare cases we might retrieve a credential with a session key this
|
||||
+ * context can't support, in which case we must retry using iteration. */
|
||||
+ if (flags & KRB5_TC_SUPPORTED_KTYPES) {
|
||||
+ ret = krb5_get_tgs_ktypes(context, cred.server, &enctypes);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ if (!k5_etypes_contains(enctypes, cred.keyblock.enctype)) {
|
||||
+ ret = k5_cc_retrieve_cred_default(context, cache, flags, mcred,
|
||||
+ cred_out);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ *cred_out = cred;
|
||||
+ memset(&cred, 0, sizeof(cred));
|
||||
+
|
||||
+cleanup:
|
||||
+ kcmreq_free(&req);
|
||||
+ krb5_free_cred_contents(context, &cred);
|
||||
+ free(enctypes);
|
||||
+ /* Heimdal's KCM returns KRB5_CC_END if no cred is found. */
|
||||
+ return (ret == KRB5_CC_END) ? KRB5_CC_NOTFOUND : map_invalid(ret);
|
||||
}
|
||||
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
diff --git a/src/tests/kcmserver.py b/src/tests/kcmserver.py
|
||||
index 8c5e66ff1..25e6f2bbe 100644
|
||||
--- a/src/tests/kcmserver.py
|
||||
+++ b/src/tests/kcmserver.py
|
||||
@@ -40,6 +40,7 @@ class KCMOpcodes(object):
|
||||
INITIALIZE = 4
|
||||
DESTROY = 5
|
||||
STORE = 6
|
||||
+ RETRIEVE = 7
|
||||
GET_PRINCIPAL = 8
|
||||
GET_CRED_UUID_LIST = 9
|
||||
GET_CRED_BY_UUID = 10
|
||||
@@ -54,6 +55,7 @@ class KCMOpcodes(object):
|
||||
|
||||
|
||||
class KRB5Errors(object):
|
||||
+ KRB5_CC_NOTFOUND = -1765328243
|
||||
KRB5_CC_END = -1765328242
|
||||
KRB5_CC_NOSUPP = -1765328137
|
||||
KRB5_FCC_NOFILE = -1765328189
|
||||
@@ -86,11 +88,29 @@ def get_cache(name):
|
||||
return cache
|
||||
|
||||
|
||||
+def unpack_data(argbytes):
|
||||
+ dlen, = struct.unpack('>L', argbytes[:4])
|
||||
+ return argbytes[4:dlen+4], argbytes[dlen+4:]
|
||||
+
|
||||
+
|
||||
def unmarshal_name(argbytes):
|
||||
offset = argbytes.find(b'\0')
|
||||
return argbytes[0:offset], argbytes[offset+1:]
|
||||
|
||||
|
||||
+def unmarshal_princ(argbytes):
|
||||
+ # Ignore the type at argbytes[0:4].
|
||||
+ ncomps, = struct.unpack('>L', argbytes[4:8])
|
||||
+ realm, rest = unpack_data(argbytes[8:])
|
||||
+ comps = []
|
||||
+ for i in range(ncomps):
|
||||
+ comp, rest = unpack_data(rest)
|
||||
+ comps.append(comp)
|
||||
+ # Asssume no quoting is needed.
|
||||
+ princ = b'/'.join(comps) + b'@' + realm
|
||||
+ return princ, rest
|
||||
+
|
||||
+
|
||||
def op_gen_new(argbytes):
|
||||
# Does not actually check for uniqueness.
|
||||
global next_unique
|
||||
@@ -126,6 +146,22 @@ def op_store(argbytes):
|
||||
return 0, b''
|
||||
|
||||
|
||||
+def op_retrieve(argbytes):
|
||||
+ name, rest = unmarshal_name(argbytes)
|
||||
+ # Ignore the flags at rest[0:4] and the header at rest[4:8].
|
||||
+ # Assume there are client and server creds in the tag and match
|
||||
+ # only against them.
|
||||
+ cprinc, rest = unmarshal_princ(rest[8:])
|
||||
+ sprinc, rest = unmarshal_princ(rest)
|
||||
+ cache = get_cache(name)
|
||||
+ for cred in (cache.creds[u] for u in cache.cred_uuids):
|
||||
+ cred_cprinc, rest = unmarshal_princ(cred)
|
||||
+ cred_sprinc, rest = unmarshal_princ(rest)
|
||||
+ if cred_cprinc == cprinc and cred_sprinc == sprinc:
|
||||
+ return 0, cred
|
||||
+ return KRB5Errors.KRB5_CC_NOTFOUND, b''
|
||||
+
|
||||
+
|
||||
def op_get_principal(argbytes):
|
||||
name, rest = unmarshal_name(argbytes)
|
||||
cache = get_cache(name)
|
||||
@@ -199,6 +235,7 @@ ophandlers = {
|
||||
KCMOpcodes.INITIALIZE : op_initialize,
|
||||
KCMOpcodes.DESTROY : op_destroy,
|
||||
KCMOpcodes.STORE : op_store,
|
||||
+ KCMOpcodes.RETRIEVE : op_retrieve,
|
||||
KCMOpcodes.GET_PRINCIPAL : op_get_principal,
|
||||
KCMOpcodes.GET_CRED_UUID_LIST : op_get_cred_uuid_list,
|
||||
KCMOpcodes.GET_CRED_BY_UUID : op_get_cred_by_uuid,
|
||||
@@ -243,10 +280,11 @@ def service_request(s):
|
||||
return True
|
||||
|
||||
parser = optparse.OptionParser()
|
||||
-parser.add_option('-c', '--credlist', action='store_true', dest='credlist',
|
||||
- default=False, help='Support KCM_OP_GET_CRED_LIST')
|
||||
+parser.add_option('-f', '--fallback', action='store_true', dest='fallback',
|
||||
+ default=False, help='Do not support RETRIEVE/GET_CRED_LIST')
|
||||
(options, args) = parser.parse_args()
|
||||
-if not options.credlist:
|
||||
+if options.fallback:
|
||||
+ del ophandlers[KCMOpcodes.RETRIEVE]
|
||||
del ophandlers[KCMOpcodes.GET_CRED_LIST]
|
||||
|
||||
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
diff --git a/src/tests/t_ccache.py b/src/tests/t_ccache.py
|
||||
index 90040fb7b..6ea9fb969 100755
|
||||
--- a/src/tests/t_ccache.py
|
||||
+++ b/src/tests/t_ccache.py
|
||||
@@ -25,7 +25,7 @@ from k5test import *
|
||||
kcm_socket_path = os.path.join(os.getcwd(), 'testdir', 'kcm')
|
||||
conf = {'libdefaults': {'kcm_socket': kcm_socket_path,
|
||||
'kcm_mach_service': '-'}}
|
||||
-realm = K5Realm(create_host=False, krb5_conf=conf)
|
||||
+realm = K5Realm(krb5_conf=conf)
|
||||
|
||||
keyctl = which('keyctl')
|
||||
out = realm.run([klist, '-c', 'KEYRING:process:abcd'], expected_code=1)
|
||||
@@ -71,6 +71,11 @@ def collection_test(realm, ccname):
|
||||
realm.kinit('alice', password('alice'))
|
||||
realm.run([klist], expected_msg='Default principal: alice@')
|
||||
realm.run([klist, '-A', '-s'])
|
||||
+ realm.run([kvno, realm.host_princ], expected_msg = 'kvno = 1')
|
||||
+ realm.run([kvno, realm.host_princ], expected_msg = 'kvno = 1')
|
||||
+ out = realm.run([klist])
|
||||
+ if out.count(realm.host_princ) != 1:
|
||||
+ fail('Wrong number of service tickets in cache')
|
||||
realm.run([kdestroy])
|
||||
output = realm.run([klist], expected_code=1)
|
||||
if 'No credentials cache' not in output and 'not found' not in output:
|
||||
@@ -126,14 +131,14 @@ def collection_test(realm, ccname):
|
||||
|
||||
collection_test(realm, 'DIR:' + os.path.join(realm.testdir, 'cc'))
|
||||
|
||||
-# Test KCM without and with GET_CRED_LIST support.
|
||||
+# Test KCM with and without RETRIEVE and GET_CRED_LIST support.
|
||||
kcmserver_path = os.path.join(srctop, 'tests', 'kcmserver.py')
|
||||
kcmd = realm.start_server([sys.executable, kcmserver_path, kcm_socket_path],
|
||||
'starting...')
|
||||
collection_test(realm, 'KCM:')
|
||||
stop_daemon(kcmd)
|
||||
os.remove(kcm_socket_path)
|
||||
-realm.start_server([sys.executable, kcmserver_path, '-c', kcm_socket_path],
|
||||
+realm.start_server([sys.executable, kcmserver_path, '-f', kcm_socket_path],
|
||||
'starting...')
|
||||
collection_test(realm, 'KCM:')
|
||||
|
@ -0,0 +1,485 @@
|
||||
From 21e3b9a4463f1d1aeb71de8a27c298f1307d186b Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Fri, 4 Oct 2019 14:49:29 -0400
|
||||
Subject: [PATCH] Use OpenSSL's KBKDF and KRB5KDF for deriving long-term keys
|
||||
|
||||
If supported, use OpenSSL-provided KBKDF (aes-sha2 and camellia) and
|
||||
KRB5KDF (3des and aes-sha1). We already use OpenSSL's PBKDF2 where
|
||||
appropriate. OpenSSL added support for these KDFs in 3.0.
|
||||
|
||||
OpenSSL's restrictions to use KRB5KDF in FIPS mode are bypassed in case
|
||||
AES SHA-1 HMAC encryption types are allowed by the crypto policy.
|
||||
|
||||
(cherry picked from commit ef8d11f6fb1232201c9efd2ae2ed567023fb85d2)
|
||||
[rharwood@redhat.com: 3des removal]
|
||||
---
|
||||
src/lib/crypto/krb/derive.c | 409 ++++++++++++++++++++++++++++--------
|
||||
1 file changed, 324 insertions(+), 85 deletions(-)
|
||||
|
||||
diff --git a/src/lib/crypto/krb/derive.c b/src/lib/crypto/krb/derive.c
|
||||
index 6707a7308..8e474b38e 100644
|
||||
--- a/src/lib/crypto/krb/derive.c
|
||||
+++ b/src/lib/crypto/krb/derive.c
|
||||
@@ -27,6 +27,12 @@
|
||||
|
||||
#include "crypto_int.h"
|
||||
|
||||
+#ifdef HAVE_EVP_KDF_FETCH
|
||||
+#include <openssl/core_names.h>
|
||||
+#include <openssl/evp.h>
|
||||
+#include <openssl/kdf.h>
|
||||
+#endif
|
||||
+
|
||||
static krb5_key
|
||||
find_cached_dkey(struct derived_key *list, const krb5_data *constant)
|
||||
{
|
||||
@@ -77,55 +83,251 @@ cleanup:
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
+#ifdef HAVE_EVP_KDF_FETCH
|
||||
static krb5_error_code
|
||||
-derive_random_rfc3961(const struct krb5_enc_provider *enc,
|
||||
- krb5_key inkey, krb5_data *outrnd,
|
||||
- const krb5_data *in_constant)
|
||||
+openssl_kbdkf_counter_hmac(const struct krb5_hash_provider *hash,
|
||||
+ krb5_key inkey, krb5_data *outrnd,
|
||||
+ const krb5_data *label, const krb5_data *context)
|
||||
{
|
||||
- size_t blocksize, keybytes, n;
|
||||
krb5_error_code ret;
|
||||
- krb5_data block = empty_data();
|
||||
+ EVP_KDF *kdf = NULL;
|
||||
+ EVP_KDF_CTX *kctx = NULL;
|
||||
+ OSSL_PARAM params[6];
|
||||
+ size_t i = 0;
|
||||
+ char *digest;
|
||||
|
||||
- blocksize = enc->block_size;
|
||||
- keybytes = enc->keybytes;
|
||||
+ /* On NULL hash, preserve default behavior for pbkdf2_string_to_key(). */
|
||||
+ if (hash == NULL || !strcmp(hash->hash_name, "SHA1")) {
|
||||
+ digest = "SHA1";
|
||||
+ } else if (!strcmp(hash->hash_name, "SHA-256")) {
|
||||
+ digest = "SHA256";
|
||||
+ } else if (!strcmp(hash->hash_name, "SHA-384")) {
|
||||
+ digest = "SHA384";
|
||||
+ } else {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
|
||||
- if (blocksize == 1)
|
||||
- return KRB5_BAD_ENCTYPE;
|
||||
- if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
|
||||
+ kdf = EVP_KDF_fetch(NULL, "KBKDF", NULL);
|
||||
+ if (!kdf) {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ kctx = EVP_KDF_CTX_new(kdf);
|
||||
+ if (!kctx) {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
|
||||
+ digest, 0);
|
||||
+ params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC,
|
||||
+ "HMAC", 0);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
|
||||
+ inkey->keyblock.contents,
|
||||
+ inkey->keyblock.length);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
|
||||
+ context->data,
|
||||
+ context->length);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
|
||||
+ label->data,
|
||||
+ label->length);
|
||||
+ params[i] = OSSL_PARAM_construct_end();
|
||||
+ if (EVP_KDF_derive(kctx, (unsigned char *)outrnd->data, outrnd->length,
|
||||
+ params) <= 0) {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ ret = 0;
|
||||
+done:
|
||||
+ if (ret)
|
||||
+ zap(outrnd->data, outrnd->length);
|
||||
+ EVP_KDF_free(kdf);
|
||||
+ EVP_KDF_CTX_free(kctx);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static krb5_error_code
|
||||
+openssl_kbkdf_feedback_cmac(const struct krb5_enc_provider *enc,
|
||||
+ krb5_key inkey, krb5_data *outrnd,
|
||||
+ const krb5_data *in_constant)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ EVP_KDF *kdf = NULL;
|
||||
+ EVP_KDF_CTX *kctx = NULL;
|
||||
+ OSSL_PARAM params[7];
|
||||
+ size_t i = 0;
|
||||
+ char *cipher;
|
||||
+ static unsigned char zeroes[16];
|
||||
+
|
||||
+ memset(zeroes, 0, sizeof(zeroes));
|
||||
+
|
||||
+ if (!memcmp(enc, &krb5int_enc_camellia128, sizeof(*enc))) {
|
||||
+ cipher = "CAMELLIA-128-CBC";
|
||||
+ } else if (!memcmp(enc, &krb5int_enc_camellia256, sizeof(*enc))) {
|
||||
+ cipher = "CAMELLIA-256-CBC";
|
||||
+ } else {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ kdf = EVP_KDF_fetch(NULL, "KBKDF", NULL);
|
||||
+ if (!kdf) {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ kctx = EVP_KDF_CTX_new(kdf);
|
||||
+ if (!kctx) {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MODE,
|
||||
+ "FEEDBACK", 0);
|
||||
+ params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC,
|
||||
+ "CMAC", 0);
|
||||
+ params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CIPHER,
|
||||
+ cipher, 0);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
|
||||
+ inkey->keyblock.contents,
|
||||
+ inkey->keyblock.length);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
|
||||
+ in_constant->data,
|
||||
+ in_constant->length);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SEED,
|
||||
+ zeroes, sizeof(zeroes));
|
||||
+ params[i] = OSSL_PARAM_construct_end();
|
||||
+ if (EVP_KDF_derive(kctx, (unsigned char *)outrnd->data, outrnd->length,
|
||||
+ params) <= 0) {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ ret = 0;
|
||||
+done:
|
||||
+ if (ret)
|
||||
+ zap(outrnd->data, outrnd->length);
|
||||
+ EVP_KDF_free(kdf);
|
||||
+ EVP_KDF_CTX_free(kctx);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static krb5_error_code
|
||||
+openssl_krb5kdf(const struct krb5_enc_provider *enc, krb5_key inkey,
|
||||
+ krb5_data *outrnd, const krb5_data *in_constant)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ EVP_KDF *kdf = NULL;
|
||||
+ EVP_KDF_CTX *kctx = NULL;
|
||||
+ OSSL_PARAM params[4];
|
||||
+ size_t i = 0;
|
||||
+ char *cipher;
|
||||
+
|
||||
+ if (inkey->keyblock.length != enc->keylength ||
|
||||
+ outrnd->length != enc->keybytes) {
|
||||
+ return KRB5_CRYPTO_INTERNAL;
|
||||
+ }
|
||||
+
|
||||
+ if (!memcmp(enc, &krb5int_enc_aes128, sizeof(*enc))) {
|
||||
+ cipher = "AES-128-CBC";
|
||||
+ } else if (!memcmp(enc, &krb5int_enc_aes256, sizeof(*enc))) {
|
||||
+ cipher = "AES-256-CBC";
|
||||
+ } else {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ kdf = EVP_KDF_fetch(NULL, "KRB5KDF", "-fips");
|
||||
+ if (kdf == NULL) {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ kctx = EVP_KDF_CTX_new(kdf);
|
||||
+ if (kctx == NULL) {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CIPHER,
|
||||
+ cipher, 0);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
|
||||
+ inkey->keyblock.contents,
|
||||
+ inkey->keyblock.length);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_CONSTANT,
|
||||
+ in_constant->data,
|
||||
+ in_constant->length);
|
||||
+ params[i] = OSSL_PARAM_construct_end();
|
||||
+ if (EVP_KDF_derive(kctx, (unsigned char *)outrnd->data, outrnd->length,
|
||||
+ params) <= 0) {
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ ret = 0;
|
||||
+done:
|
||||
+ if (ret)
|
||||
+ zap(outrnd->data, outrnd->length);
|
||||
+ EVP_KDF_free(kdf);
|
||||
+ EVP_KDF_CTX_free(kctx);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+#else /* HAVE_EVP_KDF_FETCH */
|
||||
+
|
||||
+/*
|
||||
+ * NIST SP800-108 KDF in counter mode (section 5.1).
|
||||
+ * Parameters:
|
||||
+ * - HMAC (with hash as the hash provider) is the PRF.
|
||||
+ * - A block counter of four bytes is used.
|
||||
+ * - Four bytes are used to encode the output length in the PRF input.
|
||||
+ *
|
||||
+ * There are no uses requiring more than a single PRF invocation.
|
||||
+ */
|
||||
+static krb5_error_code
|
||||
+builtin_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
|
||||
+ krb5_key inkey, krb5_data *outrnd,
|
||||
+ const krb5_data *label,
|
||||
+ const krb5_data *context)
|
||||
+{
|
||||
+ krb5_crypto_iov iov[5];
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_data prf;
|
||||
+ unsigned char ibuf[4], lbuf[4];
|
||||
+
|
||||
+ if (hash == NULL || outrnd->length > hash->hashsize)
|
||||
return KRB5_CRYPTO_INTERNAL;
|
||||
|
||||
/* Allocate encryption data buffer. */
|
||||
- ret = alloc_data(&block, blocksize);
|
||||
+ ret = alloc_data(&prf, hash->hashsize);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- /* Initialize the input block. */
|
||||
- if (in_constant->length == blocksize) {
|
||||
- memcpy(block.data, in_constant->data, blocksize);
|
||||
- } else {
|
||||
- krb5int_nfold(in_constant->length * 8,
|
||||
- (unsigned char *) in_constant->data,
|
||||
- blocksize * 8, (unsigned char *) block.data);
|
||||
- }
|
||||
+ /* [i]2: four-byte big-endian binary string giving the block counter (1) */
|
||||
+ iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
+ iov[0].data = make_data(ibuf, sizeof(ibuf));
|
||||
+ store_32_be(1, ibuf);
|
||||
+ /* Label */
|
||||
+ iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
+ iov[1].data = *label;
|
||||
+ /* 0x00: separator byte */
|
||||
+ iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
+ iov[2].data = make_data("", 1);
|
||||
+ /* Context */
|
||||
+ iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
+ iov[3].data = *context;
|
||||
+ /* [L]2: four-byte big-endian binary string giving the output length */
|
||||
+ iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
+ iov[4].data = make_data(lbuf, sizeof(lbuf));
|
||||
+ store_32_be(outrnd->length * 8, lbuf);
|
||||
|
||||
- /* Loop encrypting the blocks until enough key bytes are generated. */
|
||||
- n = 0;
|
||||
- while (n < keybytes) {
|
||||
- ret = encrypt_block(enc, inkey, &block);
|
||||
- if (ret)
|
||||
- goto cleanup;
|
||||
-
|
||||
- if ((keybytes - n) <= blocksize) {
|
||||
- memcpy(outrnd->data + n, block.data, (keybytes - n));
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- memcpy(outrnd->data + n, block.data, blocksize);
|
||||
- n += blocksize;
|
||||
- }
|
||||
-
|
||||
-cleanup:
|
||||
- zapfree(block.data, blocksize);
|
||||
+ ret = krb5int_hmac(hash, inkey, iov, 5, &prf);
|
||||
+ if (!ret)
|
||||
+ memcpy(outrnd->data, prf.data, outrnd->length);
|
||||
+ zapfree(prf.data, prf.length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -139,9 +341,9 @@ cleanup:
|
||||
* - Four bytes are used to encode the output length in the PRF input.
|
||||
*/
|
||||
static krb5_error_code
|
||||
-derive_random_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
|
||||
- krb5_key inkey, krb5_data *outrnd,
|
||||
- const krb5_data *in_constant)
|
||||
+builtin_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
|
||||
+ krb5_key inkey, krb5_data *outrnd,
|
||||
+ const krb5_data *in_constant)
|
||||
{
|
||||
size_t blocksize, keybytes, n;
|
||||
krb5_crypto_iov iov[6];
|
||||
@@ -204,56 +406,94 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * NIST SP800-108 KDF in counter mode (section 5.1).
|
||||
- * Parameters:
|
||||
- * - HMAC (with hash as the hash provider) is the PRF.
|
||||
- * - A block counter of four bytes is used.
|
||||
- * - Four bytes are used to encode the output length in the PRF input.
|
||||
- *
|
||||
- * There are no uses requiring more than a single PRF invocation.
|
||||
- */
|
||||
+static krb5_error_code
|
||||
+builtin_derive_random_rfc3961(const struct krb5_enc_provider *enc,
|
||||
+ krb5_key inkey, krb5_data *outrnd,
|
||||
+ const krb5_data *in_constant)
|
||||
+{
|
||||
+ size_t blocksize, keybytes, n;
|
||||
+ krb5_error_code ret;
|
||||
+ krb5_data block = empty_data();
|
||||
+
|
||||
+ blocksize = enc->block_size;
|
||||
+ keybytes = enc->keybytes;
|
||||
+
|
||||
+ if (blocksize == 1)
|
||||
+ return KRB5_BAD_ENCTYPE;
|
||||
+ if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
|
||||
+ return KRB5_CRYPTO_INTERNAL;
|
||||
+
|
||||
+ /* Allocate encryption data buffer. */
|
||||
+ ret = alloc_data(&block, blocksize);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Initialize the input block. */
|
||||
+ if (in_constant->length == blocksize) {
|
||||
+ memcpy(block.data, in_constant->data, blocksize);
|
||||
+ } else {
|
||||
+ krb5int_nfold(in_constant->length * 8,
|
||||
+ (unsigned char *) in_constant->data,
|
||||
+ blocksize * 8, (unsigned char *) block.data);
|
||||
+ }
|
||||
+
|
||||
+ /* Loop encrypting the blocks until enough key bytes are generated. */
|
||||
+ n = 0;
|
||||
+ while (n < keybytes) {
|
||||
+ ret = encrypt_block(enc, inkey, &block);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if ((keybytes - n) <= blocksize) {
|
||||
+ memcpy(outrnd->data + n, block.data, (keybytes - n));
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(outrnd->data + n, block.data, blocksize);
|
||||
+ n += blocksize;
|
||||
+ }
|
||||
+
|
||||
+cleanup:
|
||||
+ zapfree(block.data, blocksize);
|
||||
+ return ret;
|
||||
+}
|
||||
+#endif /* HAVE_EVP_KDF_FETCH */
|
||||
+
|
||||
krb5_error_code
|
||||
k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
|
||||
krb5_key inkey, krb5_data *outrnd,
|
||||
const krb5_data *label, const krb5_data *context)
|
||||
{
|
||||
- krb5_crypto_iov iov[5];
|
||||
- krb5_error_code ret;
|
||||
- krb5_data prf;
|
||||
- unsigned char ibuf[4], lbuf[4];
|
||||
+#ifdef HAVE_EVP_KDF_FETCH
|
||||
+ return openssl_kbdkf_counter_hmac(hash, inkey, outrnd, label, context);
|
||||
+#else
|
||||
+ return builtin_sp800_108_counter_hmac(hash, inkey, outrnd, label,
|
||||
+ context);
|
||||
+#endif
|
||||
+}
|
||||
|
||||
- if (hash == NULL || outrnd->length > hash->hashsize)
|
||||
- return KRB5_CRYPTO_INTERNAL;
|
||||
+static krb5_error_code
|
||||
+sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
|
||||
+ krb5_key inkey, krb5_data *outrnd,
|
||||
+ const krb5_data *in_constant)
|
||||
+{
|
||||
+#ifdef HAVE_EVP_KDF_FETCH
|
||||
+ return openssl_kbkdf_feedback_cmac(enc, inkey, outrnd, in_constant);
|
||||
+#else
|
||||
+ return builtin_sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant);
|
||||
+#endif
|
||||
+}
|
||||
|
||||
- /* Allocate encryption data buffer. */
|
||||
- ret = alloc_data(&prf, hash->hashsize);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* [i]2: four-byte big-endian binary string giving the block counter (1) */
|
||||
- iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
- iov[0].data = make_data(ibuf, sizeof(ibuf));
|
||||
- store_32_be(1, ibuf);
|
||||
- /* Label */
|
||||
- iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
- iov[1].data = *label;
|
||||
- /* 0x00: separator byte */
|
||||
- iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
- iov[2].data = make_data("", 1);
|
||||
- /* Context */
|
||||
- iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
- iov[3].data = *context;
|
||||
- /* [L]2: four-byte big-endian binary string giving the output length */
|
||||
- iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||
- iov[4].data = make_data(lbuf, sizeof(lbuf));
|
||||
- store_32_be(outrnd->length * 8, lbuf);
|
||||
-
|
||||
- ret = krb5int_hmac(hash, inkey, iov, 5, &prf);
|
||||
- if (!ret)
|
||||
- memcpy(outrnd->data, prf.data, outrnd->length);
|
||||
- zapfree(prf.data, prf.length);
|
||||
- return ret;
|
||||
+static krb5_error_code
|
||||
+derive_random_rfc3961(const struct krb5_enc_provider *enc,
|
||||
+ krb5_key inkey, krb5_data *outrnd,
|
||||
+ const krb5_data *in_constant)
|
||||
+{
|
||||
+#ifdef HAVE_EVP_KDF_FETCH
|
||||
+ return openssl_krb5kdf(enc, inkey, outrnd, in_constant);
|
||||
+#else
|
||||
+ return builtin_derive_random_rfc3961(enc, inkey, outrnd, in_constant);
|
||||
+#endif
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
@@ -268,8 +508,7 @@ krb5int_derive_random(const struct krb5_enc_provider *enc,
|
||||
case DERIVE_RFC3961:
|
||||
return derive_random_rfc3961(enc, inkey, outrnd, in_constant);
|
||||
case DERIVE_SP800_108_CMAC:
|
||||
- return derive_random_sp800_108_feedback_cmac(enc, inkey, outrnd,
|
||||
- in_constant);
|
||||
+ return sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant);
|
||||
case DERIVE_SP800_108_HMAC:
|
||||
return k5_sp800_108_counter_hmac(hash, inkey, outrnd, in_constant,
|
||||
&empty);
|
408
SOURCES/Use-OpenSSL-s-SSKDF-in-PKINIT-when-available.patch
Normal file
408
SOURCES/Use-OpenSSL-s-SSKDF-in-PKINIT-when-available.patch
Normal file
@ -0,0 +1,408 @@
|
||||
From 8bbb492f2be1418e1e4bb2cf197414810dac9589 Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Fri, 20 Sep 2019 17:20:59 -0400
|
||||
Subject: [PATCH] Use OpenSSL's SSKDF in PKINIT when available
|
||||
|
||||
Starting in 3.0, OpenSSL implements SSKDF, which is the basis of our
|
||||
id-pkinit-kdf (RFC 8636). Factor out common setup code around
|
||||
other_info. Adjust code to comply to existing style.
|
||||
|
||||
(cherry picked from commit 4376a22e41fb639be31daf81275a332d3f930996)
|
||||
---
|
||||
.../preauth/pkinit/pkinit_crypto_openssl.c | 294 +++++++++++-------
|
||||
1 file changed, 181 insertions(+), 113 deletions(-)
|
||||
|
||||
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||
index e1153344e..350c2118a 100644
|
||||
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||
@@ -38,6 +38,12 @@
|
||||
#include <dirent.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
+#ifdef HAVE_EVP_KDF_FETCH
|
||||
+#include <openssl/core_names.h>
|
||||
+#include <openssl/kdf.h>
|
||||
+#include <openssl/params.h>
|
||||
+#endif
|
||||
+
|
||||
static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context );
|
||||
static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context );
|
||||
|
||||
@@ -2294,15 +2300,16 @@ cleanup:
|
||||
}
|
||||
|
||||
|
||||
-/**
|
||||
+/*
|
||||
* Given an algorithm_identifier, this function returns the hash length
|
||||
* and EVP function associated with that algorithm.
|
||||
+ *
|
||||
+ * RFC 8636 defines a SHA384 variant, but we don't use it.
|
||||
*/
|
||||
static krb5_error_code
|
||||
-pkinit_alg_values(krb5_context context,
|
||||
- const krb5_data *alg_id,
|
||||
- size_t *hash_bytes,
|
||||
- const EVP_MD *(**func)(void))
|
||||
+pkinit_alg_values(krb5_context context, const krb5_data *alg_id,
|
||||
+ size_t *hash_bytes, const EVP_MD *(**func)(void),
|
||||
+ char **hash_name)
|
||||
{
|
||||
*hash_bytes = 0;
|
||||
*func = NULL;
|
||||
@@ -2311,18 +2318,21 @@ pkinit_alg_values(krb5_context context,
|
||||
krb5_pkinit_sha1_oid_len))) {
|
||||
*hash_bytes = 20;
|
||||
*func = &EVP_sha1;
|
||||
+ *hash_name = strdup("SHA1");
|
||||
return 0;
|
||||
} else if ((alg_id->length == krb5_pkinit_sha256_oid_len) &&
|
||||
(0 == memcmp(alg_id->data, krb5_pkinit_sha256_oid,
|
||||
krb5_pkinit_sha256_oid_len))) {
|
||||
*hash_bytes = 32;
|
||||
*func = &EVP_sha256;
|
||||
+ *hash_name = strdup("SHA256");
|
||||
return 0;
|
||||
} else if ((alg_id->length == krb5_pkinit_sha512_oid_len) &&
|
||||
(0 == memcmp(alg_id->data, krb5_pkinit_sha512_oid,
|
||||
krb5_pkinit_sha512_oid_len))) {
|
||||
*hash_bytes = 64;
|
||||
*func = &EVP_sha512;
|
||||
+ *hash_name = strdup("SHA512");
|
||||
return 0;
|
||||
} else {
|
||||
krb5_set_error_message(context, KRB5_ERR_BAD_S2K_PARAMS,
|
||||
@@ -2331,11 +2341,60 @@ pkinit_alg_values(krb5_context context,
|
||||
}
|
||||
} /* pkinit_alg_values() */
|
||||
|
||||
+#ifdef HAVE_EVP_KDF_FETCH
|
||||
+static krb5_error_code
|
||||
+openssl_sskdf(krb5_context context, size_t hash_bytes, krb5_data *key,
|
||||
+ krb5_data *info, char *out, size_t out_len, char *digest)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ EVP_KDF *kdf = NULL;
|
||||
+ EVP_KDF_CTX *kctx = NULL;
|
||||
+ OSSL_PARAM params[4];
|
||||
+ size_t i = 0;
|
||||
|
||||
-/* pkinit_alg_agility_kdf() --
|
||||
- * This function generates a key using the KDF described in
|
||||
- * draft_ietf_krb_wg_pkinit_alg_agility-04.txt. The algorithm is
|
||||
- * described as follows:
|
||||
+ if (digest == NULL) {
|
||||
+ ret = oerr(context, ENOMEM,
|
||||
+ _("Failed to allocate space for digest algorithm name"));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
|
||||
+ if (kdf == NULL) {
|
||||
+ ret = oerr(context, KRB5_CRYPTO_INTERNAL, _("Failed to fetch SSKDF"));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ kctx = EVP_KDF_CTX_new(kdf);
|
||||
+ if (!kctx) {
|
||||
+ ret = oerr(context, KRB5_CRYPTO_INTERNAL,
|
||||
+ _("Failed to instantiate SSKDF"));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
|
||||
+ digest, 0);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
|
||||
+ key->data, key->length);
|
||||
+ params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
|
||||
+ info->data, info->length);
|
||||
+ params[i] = OSSL_PARAM_construct_end();
|
||||
+ if (EVP_KDF_derive(kctx, (unsigned char *)out, out_len, params) <= 0) {
|
||||
+ ret = oerr(context, KRB5_CRYPTO_INTERNAL,
|
||||
+ _("Failed to derive key using SSKDF"));
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ ret = 0;
|
||||
+done:
|
||||
+ EVP_KDF_free(kdf);
|
||||
+ EVP_KDF_CTX_free(kctx);
|
||||
+ return ret;
|
||||
+}
|
||||
+#else
|
||||
+/*
|
||||
+ * Generate a key using the KDF described in RFC 8636, also known as SSKDF
|
||||
+ * (single-step kdf). Our caller precomputes `reps`, but otherwise the
|
||||
+ * algorithm is as follows:
|
||||
*
|
||||
* 1. reps = keydatalen (K) / hash length (H)
|
||||
*
|
||||
@@ -2349,95 +2408,16 @@ pkinit_alg_values(krb5_context context,
|
||||
*
|
||||
* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes.
|
||||
*/
|
||||
-krb5_error_code
|
||||
-pkinit_alg_agility_kdf(krb5_context context,
|
||||
- krb5_data *secret,
|
||||
- krb5_data *alg_oid,
|
||||
- krb5_const_principal party_u_info,
|
||||
- krb5_const_principal party_v_info,
|
||||
- krb5_enctype enctype,
|
||||
- krb5_data *as_req,
|
||||
- krb5_data *pk_as_rep,
|
||||
- krb5_keyblock *key_block)
|
||||
+static krb5_error_code
|
||||
+builtin_sskdf(krb5_context context, unsigned int reps, size_t hash_len,
|
||||
+ const EVP_MD *(*EVP_func)(void), krb5_data *secret,
|
||||
+ krb5_data *other_info, char *out, size_t out_len)
|
||||
{
|
||||
- krb5_error_code retval = 0;
|
||||
+ krb5_error_code ret = 0;
|
||||
|
||||
- unsigned int reps = 0;
|
||||
- uint32_t counter = 1; /* Does this type work on Windows? */
|
||||
+ uint32_t counter = 1;
|
||||
size_t offset = 0;
|
||||
- size_t hash_len = 0;
|
||||
- size_t rand_len = 0;
|
||||
- size_t key_len = 0;
|
||||
- krb5_data random_data;
|
||||
- krb5_sp80056a_other_info other_info_fields;
|
||||
- krb5_pkinit_supp_pub_info supp_pub_info_fields;
|
||||
- krb5_data *other_info = NULL;
|
||||
- krb5_data *supp_pub_info = NULL;
|
||||
- krb5_algorithm_identifier alg_id;
|
||||
EVP_MD_CTX *ctx = NULL;
|
||||
- const EVP_MD *(*EVP_func)(void);
|
||||
-
|
||||
- /* initialize random_data here to make clean-up safe */
|
||||
- random_data.length = 0;
|
||||
- random_data.data = NULL;
|
||||
-
|
||||
- /* allocate and initialize the key block */
|
||||
- key_block->magic = 0;
|
||||
- key_block->enctype = enctype;
|
||||
- if (0 != (retval = krb5_c_keylengths(context, enctype, &rand_len,
|
||||
- &key_len)))
|
||||
- goto cleanup;
|
||||
-
|
||||
- random_data.length = rand_len;
|
||||
- key_block->length = key_len;
|
||||
-
|
||||
- if (NULL == (key_block->contents = malloc(key_block->length))) {
|
||||
- retval = ENOMEM;
|
||||
- goto cleanup;
|
||||
- }
|
||||
-
|
||||
- memset (key_block->contents, 0, key_block->length);
|
||||
-
|
||||
- /* If this is anonymous pkinit, use the anonymous principle for party_u_info */
|
||||
- if (party_u_info && krb5_principal_compare_any_realm(context, party_u_info,
|
||||
- krb5_anonymous_principal()))
|
||||
- party_u_info = (krb5_principal)krb5_anonymous_principal();
|
||||
-
|
||||
- if (0 != (retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func)))
|
||||
- goto cleanup;
|
||||
-
|
||||
- /* 1. reps = keydatalen (K) / hash length (H) */
|
||||
- reps = key_block->length/hash_len;
|
||||
-
|
||||
- /* ... and round up, if necessary */
|
||||
- if (key_block->length > (reps * hash_len))
|
||||
- reps++;
|
||||
-
|
||||
- /* Allocate enough space in the random data buffer to hash directly into
|
||||
- * it, even if the last hash will make it bigger than the key length. */
|
||||
- if (NULL == (random_data.data = malloc(reps * hash_len))) {
|
||||
- retval = ENOMEM;
|
||||
- goto cleanup;
|
||||
- }
|
||||
-
|
||||
- /* Encode the ASN.1 octet string for "SuppPubInfo" */
|
||||
- supp_pub_info_fields.enctype = enctype;
|
||||
- supp_pub_info_fields.as_req = *as_req;
|
||||
- supp_pub_info_fields.pk_as_rep = *pk_as_rep;
|
||||
- if (0 != ((retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
|
||||
- &supp_pub_info))))
|
||||
- goto cleanup;
|
||||
-
|
||||
- /* Now encode the ASN.1 octet string for "OtherInfo" */
|
||||
- memset(&alg_id, 0, sizeof alg_id);
|
||||
- alg_id.algorithm = *alg_oid; /*alias*/
|
||||
-
|
||||
- other_info_fields.algorithm_identifier = alg_id;
|
||||
- other_info_fields.party_u_info = (krb5_principal) party_u_info;
|
||||
- other_info_fields.party_v_info = (krb5_principal) party_v_info;
|
||||
- other_info_fields.supp_pub_info = *supp_pub_info;
|
||||
- if (0 != (retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info)))
|
||||
- goto cleanup;
|
||||
|
||||
/* 2. Initialize a 32-bit, big-endian bit string counter as 1.
|
||||
* 3. For i = 1 to reps by 1, do the following:
|
||||
@@ -2450,7 +2430,7 @@ pkinit_alg_agility_kdf(krb5_context context,
|
||||
|
||||
ctx = EVP_MD_CTX_new();
|
||||
if (ctx == NULL) {
|
||||
- retval = KRB5_CRYPTO_INTERNAL;
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -2458,7 +2438,7 @@ pkinit_alg_agility_kdf(krb5_context context,
|
||||
if (!EVP_DigestInit(ctx, EVP_func())) {
|
||||
krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
|
||||
"Call to OpenSSL EVP_DigestInit() returned an error.");
|
||||
- retval = KRB5_CRYPTO_INTERNAL;
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -2467,15 +2447,16 @@ pkinit_alg_agility_kdf(krb5_context context,
|
||||
!EVP_DigestUpdate(ctx, other_info->data, other_info->length)) {
|
||||
krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
|
||||
"Call to OpenSSL EVP_DigestUpdate() returned an error.");
|
||||
- retval = KRB5_CRYPTO_INTERNAL;
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes. */
|
||||
- if (!EVP_DigestFinal(ctx, (uint8_t *)random_data.data + offset, &s)) {
|
||||
+ /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K
|
||||
+ * bytes. */
|
||||
+ if (!EVP_DigestFinal(ctx, (unsigned char *)out + offset, &s)) {
|
||||
krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
|
||||
"Call to OpenSSL EVP_DigestUpdate() returned an error.");
|
||||
- retval = KRB5_CRYPTO_INTERNAL;
|
||||
+ ret = KRB5_CRYPTO_INTERNAL;
|
||||
goto cleanup;
|
||||
}
|
||||
offset += s;
|
||||
@@ -2484,26 +2465,113 @@ pkinit_alg_agility_kdf(krb5_context context,
|
||||
EVP_MD_CTX_free(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
-
|
||||
- retval = krb5_c_random_to_key(context, enctype, &random_data,
|
||||
- key_block);
|
||||
-
|
||||
cleanup:
|
||||
EVP_MD_CTX_free(ctx);
|
||||
+ return ret;
|
||||
+} /* builtin_sskdf() */
|
||||
+#endif /* HAVE_EVP_KDF_FETCH */
|
||||
|
||||
- /* If this has been an error, free the allocated key_block, if any */
|
||||
- if (retval) {
|
||||
- krb5_free_keyblock_contents(context, key_block);
|
||||
+/* id-pkinit-kdf family, as specified by RFC 8636. */
|
||||
+krb5_error_code
|
||||
+pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
|
||||
+ krb5_data *alg_oid, krb5_const_principal party_u_info,
|
||||
+ krb5_const_principal party_v_info,
|
||||
+ krb5_enctype enctype, krb5_data *as_req,
|
||||
+ krb5_data *pk_as_rep, krb5_keyblock *key_block)
|
||||
+{
|
||||
+ krb5_error_code ret;
|
||||
+ size_t hash_len = 0, rand_len = 0, key_len = 0;
|
||||
+ const EVP_MD *(*EVP_func)(void);
|
||||
+ krb5_sp80056a_other_info other_info_fields;
|
||||
+ krb5_pkinit_supp_pub_info supp_pub_info_fields;
|
||||
+ krb5_data *other_info = NULL, *supp_pub_info = NULL;
|
||||
+ krb5_data random_data = empty_data();
|
||||
+ krb5_algorithm_identifier alg_id;
|
||||
+ unsigned int reps;
|
||||
+ char *hash_name = NULL;
|
||||
+
|
||||
+ /* Allocate and initialize the key block. */
|
||||
+ key_block->magic = 0;
|
||||
+ key_block->enctype = enctype;
|
||||
+
|
||||
+ /* Use separate variables to avoid alignment restriction problems. */
|
||||
+ ret = krb5_c_keylengths(context, enctype, &rand_len, &key_len);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+ random_data.length = rand_len;
|
||||
+ key_block->length = key_len;
|
||||
+
|
||||
+ key_block->contents = k5calloc(key_block->length, 1, &ret);
|
||||
+ if (key_block->contents == NULL)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ /* If this is anonymous pkinit, use the anonymous principle for
|
||||
+ * party_u_info. */
|
||||
+ if (party_u_info &&
|
||||
+ krb5_principal_compare_any_realm(context, party_u_info,
|
||||
+ krb5_anonymous_principal())) {
|
||||
+ party_u_info = (krb5_principal)krb5_anonymous_principal();
|
||||
}
|
||||
|
||||
- /* free other allocated resources, either way */
|
||||
- if (random_data.data)
|
||||
- free(random_data.data);
|
||||
+ ret = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func,
|
||||
+ &hash_name);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ /* 1. reps = keydatalen (K) / hash length (H) */
|
||||
+ reps = key_block->length / hash_len;
|
||||
+
|
||||
+ /* ... and round up, if necessary. */
|
||||
+ if (key_block->length > (reps * hash_len))
|
||||
+ reps++;
|
||||
+
|
||||
+ /* Allocate enough space in the random data buffer to hash directly into
|
||||
+ * it, even if the last hash will make it bigger than the key length. */
|
||||
+ random_data.data = k5alloc(reps * hash_len, &ret);
|
||||
+ if (random_data.data == NULL)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ /* Encode the ASN.1 octet string for "SuppPubInfo". */
|
||||
+ supp_pub_info_fields.enctype = enctype;
|
||||
+ supp_pub_info_fields.as_req = *as_req;
|
||||
+ supp_pub_info_fields.pk_as_rep = *pk_as_rep;
|
||||
+ ret = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
|
||||
+ &supp_pub_info);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ /* Now encode the ASN.1 octet string for "OtherInfo". */
|
||||
+ memset(&alg_id, 0, sizeof(alg_id));
|
||||
+ alg_id.algorithm = *alg_oid;
|
||||
+ other_info_fields.algorithm_identifier = alg_id;
|
||||
+ other_info_fields.party_u_info = (krb5_principal)party_u_info;
|
||||
+ other_info_fields.party_v_info = (krb5_principal)party_v_info;
|
||||
+ other_info_fields.supp_pub_info = *supp_pub_info;
|
||||
+ ret = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info);
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+#ifdef HAVE_EVP_KDF_FETCH
|
||||
+ ret = openssl_sskdf(context, hash_len, secret, other_info,
|
||||
+ random_data.data, key_block->length, hash_name);
|
||||
+#else
|
||||
+ ret = builtin_sskdf(context, reps, hash_len, EVP_func, secret,
|
||||
+ other_info, random_data.data, key_block->length);
|
||||
+#endif
|
||||
+ if (ret)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ ret = krb5_c_random_to_key(context, enctype, &random_data, key_block);
|
||||
+cleanup:
|
||||
+ if (ret)
|
||||
+ krb5_free_keyblock_contents(context, key_block);
|
||||
+
|
||||
+ free(hash_name);
|
||||
+ zapfree(random_data.data, random_data.length);
|
||||
krb5_free_data(context, other_info);
|
||||
krb5_free_data(context, supp_pub_info);
|
||||
-
|
||||
- return retval;
|
||||
-} /*pkinit_alg_agility_kdf() */
|
||||
+ return ret;
|
||||
+}
|
||||
|
||||
/* Call DH_compute_key() and ensure that we left-pad short results instead of
|
||||
* leaving junk bytes at the end of the buffer. */
|
113
SOURCES/Use-SHA256-instead-of-SHA1-for-PKINIT-CMS-digest.patch
Normal file
113
SOURCES/Use-SHA256-instead-of-SHA1-for-PKINIT-CMS-digest.patch
Normal file
@ -0,0 +1,113 @@
|
||||
From f0740c131b69f3346f07e7b7b03ebf27c50c0ccd Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Fri, 11 Mar 2022 11:33:56 +0100
|
||||
Subject: [PATCH] Use SHA-256 instead of SHA-1 for PKINIT CMS digest
|
||||
|
||||
Various organizations including NIST have been strongly recommending to
|
||||
stop using SHA-1 for digital signatures for some years already. CMS
|
||||
digest is used to generate such signatures, hence it should be upgraded
|
||||
to use SHA-256.
|
||||
---
|
||||
.../preauth/pkinit/pkinit_crypto_openssl.c | 27 ++++++++++---------
|
||||
1 file changed, 14 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||
index 42e5c581d..2a6ef4aaa 100644
|
||||
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||
@@ -1240,7 +1240,7 @@ cms_signeddata_create(krb5_context context,
|
||||
/* will not fill-out EVP_PKEY because it's on the smartcard */
|
||||
|
||||
/* Set digest algs */
|
||||
- p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
|
||||
+ p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha256);
|
||||
|
||||
if (p7si->digest_alg->parameter != NULL)
|
||||
ASN1_TYPE_free(p7si->digest_alg->parameter);
|
||||
@@ -1251,17 +1251,17 @@ cms_signeddata_create(krb5_context context,
|
||||
/* Set sig algs */
|
||||
if (p7si->digest_enc_alg->parameter != NULL)
|
||||
ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
|
||||
- p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
|
||||
+ p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha256WithRSAEncryption);
|
||||
if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
|
||||
goto cleanup;
|
||||
p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
|
||||
|
||||
/* add signed attributes */
|
||||
- /* compute sha1 digest over the EncapsulatedContentInfo */
|
||||
+ /* compute sha256 digest over the EncapsulatedContentInfo */
|
||||
ctx = EVP_MD_CTX_new();
|
||||
if (ctx == NULL)
|
||||
goto cleanup;
|
||||
- EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
|
||||
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
|
||||
EVP_DigestUpdate(ctx, data, data_len);
|
||||
md_tmp = EVP_MD_CTX_md(ctx);
|
||||
EVP_DigestFinal_ex(ctx, md_data, &md_len);
|
||||
@@ -1289,9 +1289,10 @@ cms_signeddata_create(krb5_context context,
|
||||
goto cleanup2;
|
||||
|
||||
#ifndef WITHOUT_PKCS11
|
||||
- /* Some tokens can only do RSAEncryption without sha1 hash */
|
||||
- /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
|
||||
- * function and the hash value into an ASN.1 value of type DigestInfo
|
||||
+ /* Some tokens can only do RSAEncryption without sha256 hash */
|
||||
+ /* to compute sha256WithRSAEncryption, encode the algorithm ID for the
|
||||
+ * hash function and the hash value into an ASN.1 value of type
|
||||
+ * DigestInfo
|
||||
* DigestInfo::=SEQUENCE {
|
||||
* digestAlgorithm AlgorithmIdentifier,
|
||||
* digest OCTET STRING }
|
||||
@@ -1310,7 +1311,7 @@ cms_signeddata_create(krb5_context context,
|
||||
alg = X509_ALGOR_new();
|
||||
if (alg == NULL)
|
||||
goto cleanup2;
|
||||
- X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha1), V_ASN1_NULL, NULL);
|
||||
+ X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha256), V_ASN1_NULL, NULL);
|
||||
alg_len = i2d_X509_ALGOR(alg, NULL);
|
||||
|
||||
digest = ASN1_OCTET_STRING_new();
|
||||
@@ -1339,7 +1340,7 @@ cms_signeddata_create(krb5_context context,
|
||||
#endif
|
||||
{
|
||||
pkiDebug("mech = %s\n",
|
||||
- id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
|
||||
+ id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA256_RSA_PKCS" : "FS");
|
||||
retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
|
||||
&sig, &sig_len);
|
||||
}
|
||||
@@ -4189,7 +4190,7 @@ create_signature(unsigned char **sig, unsigned int *sig_len,
|
||||
ctx = EVP_MD_CTX_new();
|
||||
if (ctx == NULL)
|
||||
return ENOMEM;
|
||||
- EVP_SignInit(ctx, EVP_sha1());
|
||||
+ EVP_SignInit(ctx, EVP_sha256());
|
||||
EVP_SignUpdate(ctx, data, data_len);
|
||||
*sig_len = EVP_PKEY_size(pkey);
|
||||
if ((*sig = malloc(*sig_len)) == NULL)
|
||||
@@ -4663,10 +4664,10 @@ pkinit_get_certs_pkcs11(krb5_context context,
|
||||
|
||||
#ifndef PKINIT_USE_MECH_LIST
|
||||
/*
|
||||
- * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
|
||||
+ * We'd like to use CKM_SHA256_RSA_PKCS for signing if it's available, but
|
||||
* many cards seems to be confused about whether they are capable of
|
||||
* this or not. The safe thing seems to be to ignore the mechanism list,
|
||||
- * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
|
||||
+ * always use CKM_RSA_PKCS and calculate the sha256 digest ourselves.
|
||||
*/
|
||||
|
||||
id_cryptoctx->mech = CKM_RSA_PKCS;
|
||||
@@ -4694,7 +4695,7 @@ pkinit_get_certs_pkcs11(krb5_context context,
|
||||
if (mechp[i] == CKM_RSA_PKCS) {
|
||||
/* This seems backwards... */
|
||||
id_cryptoctx->mech =
|
||||
- (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
|
||||
+ (info.flags & CKF_SIGN) ? CKM_SHA256_RSA_PKCS : CKM_RSA_PKCS;
|
||||
}
|
||||
}
|
||||
free(mechp);
|
||||
--
|
||||
2.35.1
|
||||
|
686
SOURCES/downstream-FIPS-with-PRNG-and-RADIUS-and-MD4.patch
Normal file
686
SOURCES/downstream-FIPS-with-PRNG-and-RADIUS-and-MD4.patch
Normal file
@ -0,0 +1,686 @@
|
||||
From a7318c3cd6e1f58adb80493c05b59e6c180cd584 Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Wed, 23 Feb 2022 17:34:33 +0100
|
||||
Subject: [PATCH] [downstream] FIPS with PRNG and RADIUS and MD4
|
||||
|
||||
NB: Use openssl's PRNG in FIPS mode and taint within krad.
|
||||
|
||||
A lot of the FIPS error conditions from OpenSSL are incredibly
|
||||
mysterious (at best, things return NULL unexpectedly; at worst,
|
||||
internal assertions are tripped; most of the time, you just get
|
||||
ENOMEM). In order to cope with this, we need to have some level of
|
||||
awareness of what we can and can't safely call.
|
||||
|
||||
This will slow down some calls slightly (FIPS_mode() takes multiple
|
||||
locks), but not for any ciphers we care about - which is to say that
|
||||
AES is fine. Shame about SPAKE though.
|
||||
|
||||
post6 restores MD4 (and therefore keygen-only RC4).
|
||||
|
||||
post7 restores MD5 and adds radius_md5_fips_override.
|
||||
|
||||
post8 restores MD4/MD5 for OpenSSL 3.0
|
||||
|
||||
Use OpenSSL 3.0 library context to access MD4 and MD5 lazily from
|
||||
legacy provider if RC4 encryption type is enabled, without affecting
|
||||
global context.
|
||||
|
||||
Remove EVP_MD_CTX_FLAG_NON_FIPS_ALLOW flag since does not have any
|
||||
effect anymore.
|
||||
|
||||
Last-updated: krb5-1.19
|
||||
---
|
||||
doc/admin/conf_files/krb5_conf.rst | 6 ++
|
||||
src/lib/crypto/krb/prng.c | 11 ++-
|
||||
.../crypto/openssl/enc_provider/camellia.c | 6 ++
|
||||
src/lib/crypto/openssl/enc_provider/rc4.c | 13 +++-
|
||||
.../crypto/openssl/hash_provider/hash_evp.c | 85 ++++++++++++++++++-
|
||||
src/lib/crypto/openssl/hmac.c | 6 +-
|
||||
src/lib/krad/attr.c | 46 ++++++++---
|
||||
src/lib/krad/attrset.c | 5 +-
|
||||
src/lib/krad/internal.h | 28 ++++++-
|
||||
src/lib/krad/packet.c | 22 +++---
|
||||
src/lib/krad/remote.c | 10 ++-
|
||||
src/lib/krad/t_attr.c | 3 +-
|
||||
src/lib/krad/t_attrset.c | 4 +-
|
||||
src/plugins/preauth/spake/spake_client.c | 6 ++
|
||||
src/plugins/preauth/spake/spake_kdc.c | 6 ++
|
||||
15 files changed, 218 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
|
||||
index 675175955..adba8238d 100644
|
||||
--- a/doc/admin/conf_files/krb5_conf.rst
|
||||
+++ b/doc/admin/conf_files/krb5_conf.rst
|
||||
@@ -330,6 +330,12 @@ The libdefaults section may contain any of the following relations:
|
||||
qualification of shortnames, set this relation to the empty string
|
||||
with ``qualify_shortname = ""``. (New in release 1.18.)
|
||||
|
||||
+**radius_md5_fips_override**
|
||||
+ Downstream-only option to enable use of MD5 in RADIUS
|
||||
+ communication (libkrad). This allows for local (or protected
|
||||
+ tunnel) communication with a RADIUS server that doesn't use krad
|
||||
+ (e.g., freeradius) while in FIPS mode.
|
||||
+
|
||||
**rdns**
|
||||
If this flag is true, reverse name lookup will be used in addition
|
||||
to forward name lookup to canonicalizing hostnames for use in
|
||||
diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c
|
||||
index cb9ca9b98..f0e9984ca 100644
|
||||
--- a/src/lib/crypto/krb/prng.c
|
||||
+++ b/src/lib/crypto/krb/prng.c
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#include "crypto_int.h"
|
||||
|
||||
+#include <openssl/rand.h>
|
||||
+
|
||||
krb5_error_code KRB5_CALLCONV
|
||||
krb5_c_random_seed(krb5_context context, krb5_data *data)
|
||||
{
|
||||
@@ -99,9 +101,16 @@ krb5_boolean
|
||||
k5_get_os_entropy(unsigned char *buf, size_t len, int strong)
|
||||
{
|
||||
const char *device;
|
||||
-#if defined(__linux__) && defined(SYS_getrandom)
|
||||
int r;
|
||||
|
||||
+ /* A wild FIPS mode appeared! */
|
||||
+ if (FIPS_mode()) {
|
||||
+ /* The return codes on this API are not good */
|
||||
+ r = RAND_bytes(buf, len);
|
||||
+ return r == 1;
|
||||
+ }
|
||||
+
|
||||
+#if defined(__linux__) && defined(SYS_getrandom)
|
||||
while (len > 0) {
|
||||
/*
|
||||
* Pull from the /dev/urandom pool, but require it to have been seeded.
|
||||
diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
|
||||
index 2da691329..f79679a0b 100644
|
||||
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
|
||||
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
|
||||
@@ -304,6 +304,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
|
||||
unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE];
|
||||
struct iov_cursor cursor;
|
||||
|
||||
+ if (FIPS_mode())
|
||||
+ return KRB5_CRYPTO_INTERNAL;
|
||||
+
|
||||
if (output->length < CAMELLIA_BLOCK_SIZE)
|
||||
return KRB5_BAD_MSIZE;
|
||||
|
||||
@@ -331,6 +334,9 @@ static krb5_error_code
|
||||
krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
|
||||
krb5_data *state)
|
||||
{
|
||||
+ if (FIPS_mode())
|
||||
+ return KRB5_CRYPTO_INTERNAL;
|
||||
+
|
||||
state->length = 16;
|
||||
state->data = (void *) malloc(16);
|
||||
if (state->data == NULL)
|
||||
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
|
||||
index bc87c6f42..9bf407899 100644
|
||||
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
|
||||
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
|
||||
@@ -66,6 +66,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
|
||||
EVP_CIPHER_CTX *ctx = NULL;
|
||||
struct arcfour_state *arcstate;
|
||||
|
||||
+ if (FIPS_mode())
|
||||
+ return KRB5_CRYPTO_INTERNAL;
|
||||
+
|
||||
arcstate = (state != NULL) ? (void *)state->data : NULL;
|
||||
if (arcstate != NULL) {
|
||||
ctx = arcstate->ctx;
|
||||
@@ -113,7 +116,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
|
||||
static void
|
||||
k5_arcfour_free_state(krb5_data *state)
|
||||
{
|
||||
- struct arcfour_state *arcstate = (void *)state->data;
|
||||
+ struct arcfour_state *arcstate;
|
||||
+
|
||||
+ if (FIPS_mode())
|
||||
+ return;
|
||||
+
|
||||
+ arcstate = (void *) state->data;
|
||||
|
||||
EVP_CIPHER_CTX_free(arcstate->ctx);
|
||||
free(arcstate);
|
||||
@@ -125,6 +133,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
|
||||
{
|
||||
struct arcfour_state *arcstate;
|
||||
|
||||
+ if (FIPS_mode())
|
||||
+ return KRB5_CRYPTO_INTERNAL;
|
||||
+
|
||||
/*
|
||||
* The cipher state here is a saved pointer to a struct arcfour_state
|
||||
* object, rather than a flat byte array as in most enc providers. The
|
||||
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
||||
index 1e0fb8fc3..4b8e1a6b2 100644
|
||||
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
||||
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
||||
@@ -32,6 +32,50 @@
|
||||
|
||||
#include "crypto_int.h"
|
||||
#include <openssl/evp.h>
|
||||
+#include <openssl/provider.h>
|
||||
+#include <threads.h>
|
||||
+
|
||||
+typedef struct ossl_lib_md_context {
|
||||
+ OSSL_LIB_CTX *libctx;
|
||||
+ OSSL_PROVIDER *legacy_provider;
|
||||
+ EVP_MD *md;
|
||||
+} 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.
|
||||
+ * If they fail keep going and an error will be raised when we try to
|
||||
+ * fetch the cipher later.
|
||||
+ */
|
||||
+ ctx->legacy_provider = OSSL_PROVIDER_load(ctx->libctx, "legacy");
|
||||
+
|
||||
+ ctx->md = EVP_MD_fetch(ctx->libctx, algo, NULL);
|
||||
+ if (!ctx->md)
|
||||
+ return KRB5_CRYPTO_INTERNAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+deinit_ossl_ctx(ossl_md_context_t *ctx)
|
||||
+{
|
||||
+ if (ctx->md)
|
||||
+ EVP_MD_free(ctx->md);
|
||||
+
|
||||
+ if (ctx->legacy_provider)
|
||||
+ OSSL_PROVIDER_unload(ctx->legacy_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,
|
||||
@@ -61,16 +104,53 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
|
||||
return ok ? 0 : KRB5_CRYPTO_INTERNAL;
|
||||
}
|
||||
|
||||
+static krb5_error_code
|
||||
+hash_legacy_evp(const char *algo, const krb5_crypto_iov *data, size_t num_data,
|
||||
+ krb5_data *output)
|
||||
+{
|
||||
+ krb5_error_code err;
|
||||
+
|
||||
+ if (!ossl_md_ctx) {
|
||||
+ ossl_md_ctx = malloc(sizeof(ossl_md_context_t));
|
||||
+ if (!ossl_md_ctx)
|
||||
+ return ENOMEM;
|
||||
+
|
||||
+ 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 = hash_evp(ossl_md_ctx->md, data, num_data, output);
|
||||
+
|
||||
+end:
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static krb5_error_code
|
||||
hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
|
||||
{
|
||||
- return hash_evp(EVP_md4(), data, num_data, output);
|
||||
+ /*
|
||||
+ * MD4 is needed in FIPS mode to perform key generation for RC4 keys used
|
||||
+ * by IPA. These keys are only used along a (separately) secured channel
|
||||
+ * for legacy reasons when performing trusts to Active Directory.
|
||||
+ */
|
||||
+ return FIPS_mode() ? hash_legacy_evp("MD4", data, num_data, output)
|
||||
+ : hash_evp(EVP_md4(), data, num_data, output);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
|
||||
{
|
||||
- return hash_evp(EVP_md5(), data, num_data, output);
|
||||
+ /*
|
||||
+ * MD5 is needed in FIPS mode for communication with RADIUS servers. This
|
||||
+ * is gated in libkrad by libdefaults->radius_md5_fips_override.
|
||||
+ */
|
||||
+ return FIPS_mode() ? hash_legacy_evp("MD5", data, num_data, output)
|
||||
+ : hash_evp(EVP_md5(), data, num_data, output);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
|
||||
index 7dc59dcc0..769a50c00 100644
|
||||
--- a/src/lib/crypto/openssl/hmac.c
|
||||
+++ b/src/lib/crypto/openssl/hmac.c
|
||||
@@ -103,7 +103,11 @@ map_digest(const struct krb5_hash_provider *hash)
|
||||
return EVP_sha256();
|
||||
else if (!strncmp(hash->hash_name, "SHA-384",7))
|
||||
return EVP_sha384();
|
||||
- else if (!strncmp(hash->hash_name, "MD5", 3))
|
||||
+
|
||||
+ if (FIPS_mode())
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (!strncmp(hash->hash_name, "MD5", 3))
|
||||
return EVP_md5();
|
||||
else if (!strncmp(hash->hash_name, "MD4", 3))
|
||||
return EVP_md4();
|
||||
diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
|
||||
index 9c13d9d75..42d354a3b 100644
|
||||
--- a/src/lib/krad/attr.c
|
||||
+++ b/src/lib/krad/attr.c
|
||||
@@ -38,7 +38,8 @@
|
||||
typedef krb5_error_code
|
||||
(*attribute_transform_fn)(krb5_context ctx, const char *secret,
|
||||
const unsigned char *auth, const krb5_data *in,
|
||||
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
||||
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||
+ krb5_boolean *is_fips);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
@@ -51,12 +52,14 @@ typedef struct {
|
||||
static krb5_error_code
|
||||
user_password_encode(krb5_context ctx, const char *secret,
|
||||
const unsigned char *auth, const krb5_data *in,
|
||||
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
||||
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||
+ krb5_boolean *is_fips);
|
||||
|
||||
static krb5_error_code
|
||||
user_password_decode(krb5_context ctx, const char *secret,
|
||||
const unsigned char *auth, const krb5_data *in,
|
||||
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
||||
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||
+ krb5_boolean *ignored);
|
||||
|
||||
static const attribute_record attributes[UCHAR_MAX] = {
|
||||
{"User-Name", 1, MAX_ATTRSIZE, NULL, NULL},
|
||||
@@ -128,7 +131,8 @@ static const attribute_record attributes[UCHAR_MAX] = {
|
||||
static krb5_error_code
|
||||
user_password_encode(krb5_context ctx, const char *secret,
|
||||
const unsigned char *auth, const krb5_data *in,
|
||||
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
||||
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||
+ krb5_boolean *is_fips)
|
||||
{
|
||||
const unsigned char *indx;
|
||||
krb5_error_code retval;
|
||||
@@ -154,8 +158,15 @@ user_password_encode(krb5_context ctx, const char *secret,
|
||||
for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) {
|
||||
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
|
||||
|
||||
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
|
||||
- &sum);
|
||||
+ if (kr_use_fips(ctx)) {
|
||||
+ /* Skip encryption here. Taint so that we won't pass it out of
|
||||
+ * the machine by accident. */
|
||||
+ *is_fips = TRUE;
|
||||
+ sum.contents = calloc(1, BLOCKSIZE);
|
||||
+ } else {
|
||||
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
|
||||
+ &sum);
|
||||
+ }
|
||||
if (retval != 0) {
|
||||
zap(tmp.data, tmp.length);
|
||||
zap(outbuf, len);
|
||||
@@ -180,7 +191,8 @@ user_password_encode(krb5_context ctx, const char *secret,
|
||||
static krb5_error_code
|
||||
user_password_decode(krb5_context ctx, const char *secret,
|
||||
const unsigned char *auth, const krb5_data *in,
|
||||
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
||||
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||
+ krb5_boolean *is_fips)
|
||||
{
|
||||
const unsigned char *indx;
|
||||
krb5_error_code retval;
|
||||
@@ -204,8 +216,15 @@ user_password_decode(krb5_context ctx, const char *secret,
|
||||
for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) {
|
||||
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
|
||||
|
||||
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
|
||||
- &tmp, &sum);
|
||||
+ if (kr_use_fips(ctx)) {
|
||||
+ /* Skip encryption here. Taint so that we won't pass it out of
|
||||
+ * the machine by accident. */
|
||||
+ *is_fips = TRUE;
|
||||
+ sum.contents = calloc(1, BLOCKSIZE);
|
||||
+ } else {
|
||||
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
|
||||
+ &tmp, &sum);
|
||||
+ }
|
||||
if (retval != 0) {
|
||||
zap(tmp.data, tmp.length);
|
||||
zap(outbuf, in->length);
|
||||
@@ -248,7 +267,7 @@ krb5_error_code
|
||||
kr_attr_encode(krb5_context ctx, const char *secret,
|
||||
const unsigned char *auth, krad_attr type,
|
||||
const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE],
|
||||
- size_t *outlen)
|
||||
+ size_t *outlen, krb5_boolean *is_fips)
|
||||
{
|
||||
krb5_error_code retval;
|
||||
|
||||
@@ -265,7 +284,8 @@ kr_attr_encode(krb5_context ctx, const char *secret,
|
||||
return 0;
|
||||
}
|
||||
|
||||
- return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen);
|
||||
+ return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen,
|
||||
+ is_fips);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
@@ -274,6 +294,7 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
||||
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
||||
{
|
||||
krb5_error_code retval;
|
||||
+ krb5_boolean ignored;
|
||||
|
||||
retval = kr_attr_valid(type, in);
|
||||
if (retval != 0)
|
||||
@@ -288,7 +309,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
||||
return 0;
|
||||
}
|
||||
|
||||
- return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen);
|
||||
+ return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen,
|
||||
+ &ignored);
|
||||
}
|
||||
|
||||
krad_attr
|
||||
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
|
||||
index 03c613716..d89982a13 100644
|
||||
--- a/src/lib/krad/attrset.c
|
||||
+++ b/src/lib/krad/attrset.c
|
||||
@@ -167,7 +167,8 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
|
||||
krb5_error_code
|
||||
kr_attrset_encode(const krad_attrset *set, const char *secret,
|
||||
const unsigned char *auth,
|
||||
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
|
||||
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
|
||||
+ krb5_boolean *is_fips)
|
||||
{
|
||||
unsigned char buffer[MAX_ATTRSIZE];
|
||||
krb5_error_code retval;
|
||||
@@ -181,7 +182,7 @@ kr_attrset_encode(const krad_attrset *set, const char *secret,
|
||||
|
||||
K5_TAILQ_FOREACH(a, &set->list, list) {
|
||||
retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
|
||||
- buffer, &attrlen);
|
||||
+ buffer, &attrlen, is_fips);
|
||||
if (retval != 0)
|
||||
return retval;
|
||||
|
||||
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
|
||||
index 0143d155a..223ffd730 100644
|
||||
--- a/src/lib/krad/internal.h
|
||||
+++ b/src/lib/krad/internal.h
|
||||
@@ -39,6 +39,8 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
+#include <openssl/crypto.h>
|
||||
+
|
||||
#ifndef UCHAR_MAX
|
||||
#define UCHAR_MAX 255
|
||||
#endif
|
||||
@@ -49,6 +51,13 @@
|
||||
|
||||
typedef struct krad_remote_st krad_remote;
|
||||
|
||||
+struct krad_packet_st {
|
||||
+ char buffer[KRAD_PACKET_SIZE_MAX];
|
||||
+ krad_attrset *attrset;
|
||||
+ krb5_data pkt;
|
||||
+ krb5_boolean is_fips;
|
||||
+};
|
||||
+
|
||||
/* Validate constraints of an attribute. */
|
||||
krb5_error_code
|
||||
kr_attr_valid(krad_attr type, const krb5_data *data);
|
||||
@@ -57,7 +66,8 @@ kr_attr_valid(krad_attr type, const krb5_data *data);
|
||||
krb5_error_code
|
||||
kr_attr_encode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
||||
krad_attr type, const krb5_data *in,
|
||||
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
||||
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||
+ krb5_boolean *is_fips);
|
||||
|
||||
/* Decode an attribute. */
|
||||
krb5_error_code
|
||||
@@ -69,7 +79,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
||||
krb5_error_code
|
||||
kr_attrset_encode(const krad_attrset *set, const char *secret,
|
||||
const unsigned char *auth,
|
||||
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen);
|
||||
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
|
||||
+ krb5_boolean *is_fips);
|
||||
|
||||
/* Decode attributes from a buffer. */
|
||||
krb5_error_code
|
||||
@@ -152,4 +163,17 @@ gai_error_code(int err)
|
||||
}
|
||||
}
|
||||
|
||||
+static inline krb5_boolean
|
||||
+kr_use_fips(krb5_context ctx)
|
||||
+{
|
||||
+ int val = 0;
|
||||
+
|
||||
+ if (!FIPS_mode())
|
||||
+ return 0;
|
||||
+
|
||||
+ profile_get_boolean(ctx->profile, "libdefaults",
|
||||
+ "radius_md5_fips_override", NULL, 0, &val);
|
||||
+ return !val;
|
||||
+}
|
||||
+
|
||||
#endif /* INTERNAL_H_ */
|
||||
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
|
||||
index c597174b6..fc2d24800 100644
|
||||
--- a/src/lib/krad/packet.c
|
||||
+++ b/src/lib/krad/packet.c
|
||||
@@ -53,12 +53,6 @@ typedef unsigned char uchar;
|
||||
#define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH))
|
||||
#define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR))
|
||||
|
||||
-struct krad_packet_st {
|
||||
- char buffer[KRAD_PACKET_SIZE_MAX];
|
||||
- krad_attrset *attrset;
|
||||
- krb5_data pkt;
|
||||
-};
|
||||
-
|
||||
typedef struct {
|
||||
uchar x[(UCHAR_MAX + 1) / 8];
|
||||
} idmap;
|
||||
@@ -187,8 +181,14 @@ auth_generate_response(krb5_context ctx, const char *secret,
|
||||
memcpy(data.data + response->pkt.length, secret, strlen(secret));
|
||||
|
||||
/* Hash it. */
|
||||
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
|
||||
- &hash);
|
||||
+ if (kr_use_fips(ctx)) {
|
||||
+ /* This checksum does very little security-wise anyway, so don't
|
||||
+ * taint. */
|
||||
+ hash.contents = calloc(1, AUTH_FIELD_SIZE);
|
||||
+ } else {
|
||||
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
|
||||
+ &hash);
|
||||
+ }
|
||||
free(data.data);
|
||||
if (retval != 0)
|
||||
return retval;
|
||||
@@ -276,7 +276,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
|
||||
|
||||
/* Encode the attributes. */
|
||||
retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt),
|
||||
- &attrset_len);
|
||||
+ &attrset_len, &pkt->is_fips);
|
||||
if (retval != 0)
|
||||
goto error;
|
||||
|
||||
@@ -314,7 +314,7 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
|
||||
|
||||
/* Encode the attributes. */
|
||||
retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt),
|
||||
- &attrset_len);
|
||||
+ &attrset_len, &pkt->is_fips);
|
||||
if (retval != 0)
|
||||
goto error;
|
||||
|
||||
@@ -451,6 +451,8 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
|
||||
const krb5_data *
|
||||
krad_packet_encode(const krad_packet *pkt)
|
||||
{
|
||||
+ if (pkt->is_fips)
|
||||
+ return NULL;
|
||||
return &pkt->pkt;
|
||||
}
|
||||
|
||||
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
|
||||
index c96a9b4ee..eca432424 100644
|
||||
--- a/src/lib/krad/remote.c
|
||||
+++ b/src/lib/krad/remote.c
|
||||
@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr)
|
||||
request *r;
|
||||
|
||||
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
||||
- tmp = krad_packet_encode(r->request);
|
||||
+ tmp = &r->request->pkt;
|
||||
|
||||
/* If the packet has already been sent, do nothing. */
|
||||
if (r->sent == tmp->length)
|
||||
@@ -359,7 +359,7 @@ on_io_read(krad_remote *rr)
|
||||
if (req != NULL) {
|
||||
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
||||
if (r->request == req &&
|
||||
- r->sent == krad_packet_encode(req)->length) {
|
||||
+ r->sent == req->pkt.length) {
|
||||
request_finish(r, 0, rsp);
|
||||
break;
|
||||
}
|
||||
@@ -455,6 +455,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
|
||||
(krad_packet_iter_cb)iterator, &r, &tmp);
|
||||
if (retval != 0)
|
||||
goto error;
|
||||
+ else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL &&
|
||||
+ rr->info->ai_family != AF_UNIX) {
|
||||
+ /* This would expose cleartext passwords, so abort. */
|
||||
+ retval = ESOCKTNOSUPPORT;
|
||||
+ goto error;
|
||||
+ }
|
||||
|
||||
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
||||
if (r->request == tmp) {
|
||||
diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c
|
||||
index eb2a780c8..4d285ad9d 100644
|
||||
--- a/src/lib/krad/t_attr.c
|
||||
+++ b/src/lib/krad/t_attr.c
|
||||
@@ -50,6 +50,7 @@ main()
|
||||
const char *tmp;
|
||||
krb5_data in;
|
||||
size_t len;
|
||||
+ krb5_boolean is_fips = FALSE;
|
||||
|
||||
noerror(krb5_init_context(&ctx));
|
||||
|
||||
@@ -73,7 +74,7 @@ main()
|
||||
in = string2data((char *)decoded);
|
||||
retval = kr_attr_encode(ctx, secret, auth,
|
||||
krad_attr_name2num("User-Password"),
|
||||
- &in, outbuf, &len);
|
||||
+ &in, outbuf, &len, &is_fips);
|
||||
insist(retval == 0);
|
||||
insist(len == sizeof(encoded));
|
||||
insist(memcmp(outbuf, encoded, len) == 0);
|
||||
diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
|
||||
index 7928335ca..0f9576253 100644
|
||||
--- a/src/lib/krad/t_attrset.c
|
||||
+++ b/src/lib/krad/t_attrset.c
|
||||
@@ -49,6 +49,7 @@ main()
|
||||
krb5_context ctx;
|
||||
size_t len = 0, encode_len;
|
||||
krb5_data tmp;
|
||||
+ krb5_boolean is_fips = FALSE;
|
||||
|
||||
noerror(krb5_init_context(&ctx));
|
||||
noerror(krad_attrset_new(ctx, &set));
|
||||
@@ -62,7 +63,8 @@ main()
|
||||
noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp));
|
||||
|
||||
/* Encode attrset. */
|
||||
- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len));
|
||||
+ noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len,
|
||||
+ &is_fips));
|
||||
krad_attrset_free(set);
|
||||
|
||||
/* Manually encode User-Name. */
|
||||
diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
|
||||
index 00734a13b..a3ce22b70 100644
|
||||
--- a/src/plugins/preauth/spake/spake_client.c
|
||||
+++ b/src/plugins/preauth/spake/spake_client.c
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "groups.h"
|
||||
#include <krb5/clpreauth_plugin.h>
|
||||
|
||||
+#include <openssl/crypto.h>
|
||||
+
|
||||
typedef struct reqstate_st {
|
||||
krb5_pa_spake *msg; /* set in prep_questions, used in process */
|
||||
krb5_keyblock *initial_key;
|
||||
@@ -375,6 +377,10 @@ clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
|
||||
|
||||
if (maj_ver != 1)
|
||||
return KRB5_PLUGIN_VER_NOTSUPP;
|
||||
+
|
||||
+ if (FIPS_mode())
|
||||
+ return KRB5_CRYPTO_INTERNAL;
|
||||
+
|
||||
vt = (krb5_clpreauth_vtable)vtable;
|
||||
vt->name = "spake";
|
||||
vt->pa_type_list = pa_types;
|
||||
diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
|
||||
index 88c964ce1..c7df0392f 100644
|
||||
--- a/src/plugins/preauth/spake/spake_kdc.c
|
||||
+++ b/src/plugins/preauth/spake/spake_kdc.c
|
||||
@@ -41,6 +41,8 @@
|
||||
|
||||
#include <krb5/kdcpreauth_plugin.h>
|
||||
|
||||
+#include <openssl/crypto.h>
|
||||
+
|
||||
/*
|
||||
* The SPAKE kdcpreauth module uses a secure cookie containing the following
|
||||
* concatenated fields (all integer fields are big-endian):
|
||||
@@ -571,6 +573,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
|
||||
|
||||
if (maj_ver != 1)
|
||||
return KRB5_PLUGIN_VER_NOTSUPP;
|
||||
+
|
||||
+ if (FIPS_mode())
|
||||
+ return KRB5_CRYPTO_INTERNAL;
|
||||
+
|
||||
vt = (krb5_kdcpreauth_vtable)vtable;
|
||||
vt->name = "spake";
|
||||
vt->pa_type_list = pa_types;
|
6453
SOURCES/downstream-Remove-3des-support.patch
Normal file
6453
SOURCES/downstream-Remove-3des-support.patch
Normal file
File diff suppressed because it is too large
Load Diff
1034
SOURCES/downstream-SELinux-integration.patch
Normal file
1034
SOURCES/downstream-SELinux-integration.patch
Normal file
File diff suppressed because it is too large
Load Diff
41
SOURCES/downstream-fix-debuginfo-with-y.tab.c.patch
Normal file
41
SOURCES/downstream-fix-debuginfo-with-y.tab.c.patch
Normal file
@ -0,0 +1,41 @@
|
||||
From d5ea86ef491feb38f12e6aa53b7579ac02675df6 Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Tue, 23 Aug 2016 16:49:25 -0400
|
||||
Subject: [PATCH] [downstream] fix debuginfo with y.tab.c
|
||||
|
||||
We want to keep these y.tab.c files around because the debuginfo points to
|
||||
them. It would be more elegant at the end to use symbolic links, but that
|
||||
could mess up people working in the tree on other things.
|
||||
|
||||
Last-updated: krb5-1.9
|
||||
---
|
||||
src/kadmin/cli/Makefile.in | 5 +++++
|
||||
src/plugins/kdb/ldap/ldap_util/Makefile.in | 2 +-
|
||||
2 files changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/kadmin/cli/Makefile.in b/src/kadmin/cli/Makefile.in
|
||||
index adfea6e2b..d1327e400 100644
|
||||
--- a/src/kadmin/cli/Makefile.in
|
||||
+++ b/src/kadmin/cli/Makefile.in
|
||||
@@ -37,3 +37,8 @@ clean-unix::
|
||||
# CC_LINK is not meant for compilation and this use may break in the future.
|
||||
datetest: getdate.c
|
||||
$(CC_LINK) $(ALL_CFLAGS) -DTEST -o datetest getdate.c
|
||||
+
|
||||
+%.c: %.y
|
||||
+ $(RM) y.tab.c $@
|
||||
+ $(YACC.y) $<
|
||||
+ $(CP) y.tab.c $@
|
||||
diff --git a/src/plugins/kdb/ldap/ldap_util/Makefile.in b/src/plugins/kdb/ldap/ldap_util/Makefile.in
|
||||
index 8669c2436..a22f23c02 100644
|
||||
--- a/src/plugins/kdb/ldap/ldap_util/Makefile.in
|
||||
+++ b/src/plugins/kdb/ldap/ldap_util/Makefile.in
|
||||
@@ -20,7 +20,7 @@ $(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIB) $(GETDATE)
|
||||
getdate.c: $(GETDATE)
|
||||
$(RM) getdate.c y.tab.c
|
||||
$(YACC) $(GETDATE)
|
||||
- $(MV) y.tab.c getdate.c
|
||||
+ $(CP) y.tab.c getdate.c
|
||||
|
||||
install:
|
||||
$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
|
774
SOURCES/downstream-ksu-pam-integration.patch
Normal file
774
SOURCES/downstream-ksu-pam-integration.patch
Normal file
@ -0,0 +1,774 @@
|
||||
From 90ba715be48c2e1b6c7ca53cb1d75f3af2c388d6 Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Tue, 23 Aug 2016 16:29:58 -0400
|
||||
Subject: [PATCH] [downstream] ksu pam integration
|
||||
|
||||
Modify ksu so that it performs account and session management on behalf of
|
||||
the target user account, mimicking the action of regular su. The default
|
||||
service name is "ksu", because on Fedora at least the configuration used
|
||||
is determined by whether or not a login shell is being opened, and so
|
||||
this may need to vary, too. At run-time, ksu's behavior can be reset to
|
||||
the earlier, non-PAM behavior by setting "use_pam" to false in the [ksu]
|
||||
section of /etc/krb5.conf.
|
||||
|
||||
When enabled, ksu gains a dependency on libpam.
|
||||
|
||||
Originally RT#5939, though it's changed since then to perform the account
|
||||
and session management before dropping privileges, and to apply on top of
|
||||
changes we're proposing for how it handles cache collections.
|
||||
|
||||
Last-updated: krb5-1.18-beta1
|
||||
---
|
||||
src/aclocal.m4 | 69 +++++++
|
||||
src/clients/ksu/Makefile.in | 8 +-
|
||||
src/clients/ksu/main.c | 88 +++++++-
|
||||
src/clients/ksu/pam.c | 389 ++++++++++++++++++++++++++++++++++++
|
||||
src/clients/ksu/pam.h | 57 ++++++
|
||||
src/configure.ac | 2 +
|
||||
6 files changed, 610 insertions(+), 3 deletions(-)
|
||||
create mode 100644 src/clients/ksu/pam.c
|
||||
create mode 100644 src/clients/ksu/pam.h
|
||||
|
||||
diff --git a/src/aclocal.m4 b/src/aclocal.m4
|
||||
index 024d6370c..ca9fcf664 100644
|
||||
--- a/src/aclocal.m4
|
||||
+++ b/src/aclocal.m4
|
||||
@@ -1677,3 +1677,72 @@ if test "$with_ldap" = yes; then
|
||||
OPENLDAP_PLUGIN=yes
|
||||
fi
|
||||
])dnl
|
||||
+dnl
|
||||
+dnl
|
||||
+dnl Use PAM instead of local crypt() compare for checking local passwords,
|
||||
+dnl and perform PAM account, session management, and password-changing where
|
||||
+dnl appropriate.
|
||||
+dnl
|
||||
+AC_DEFUN(KRB5_WITH_PAM,[
|
||||
+AC_ARG_WITH(pam,[AC_HELP_STRING(--with-pam,[compile with PAM support])],
|
||||
+ withpam="$withval",withpam=auto)
|
||||
+AC_ARG_WITH(pam-ksu-service,[AC_HELP_STRING(--with-ksu-service,[PAM service name for ksu ["ksu"]])],
|
||||
+ withksupamservice="$withval",withksupamservice=ksu)
|
||||
+old_LIBS="$LIBS"
|
||||
+if test "$withpam" != no ; then
|
||||
+ AC_MSG_RESULT([checking for PAM...])
|
||||
+ PAM_LIBS=
|
||||
+
|
||||
+ AC_CHECK_HEADERS(security/pam_appl.h)
|
||||
+ if test "x$ac_cv_header_security_pam_appl_h" != xyes ; then
|
||||
+ if test "$withpam" = auto ; then
|
||||
+ AC_MSG_RESULT([Unable to locate security/pam_appl.h.])
|
||||
+ withpam=no
|
||||
+ else
|
||||
+ AC_MSG_ERROR([Unable to locate security/pam_appl.h.])
|
||||
+ fi
|
||||
+ fi
|
||||
+
|
||||
+ LIBS=
|
||||
+ unset ac_cv_func_pam_start
|
||||
+ AC_CHECK_FUNCS(putenv pam_start)
|
||||
+ if test "x$ac_cv_func_pam_start" = xno ; then
|
||||
+ unset ac_cv_func_pam_start
|
||||
+ AC_CHECK_LIB(dl,dlopen)
|
||||
+ AC_CHECK_FUNCS(pam_start)
|
||||
+ if test "x$ac_cv_func_pam_start" = xno ; then
|
||||
+ AC_CHECK_LIB(pam,pam_start)
|
||||
+ unset ac_cv_func_pam_start
|
||||
+ unset ac_cv_func_pam_getenvlist
|
||||
+ AC_CHECK_FUNCS(pam_start pam_getenvlist)
|
||||
+ if test "x$ac_cv_func_pam_start" = xyes ; then
|
||||
+ PAM_LIBS="$LIBS"
|
||||
+ else
|
||||
+ if test "$withpam" = auto ; then
|
||||
+ AC_MSG_RESULT([Unable to locate libpam.])
|
||||
+ withpam=no
|
||||
+ else
|
||||
+ AC_MSG_ERROR([Unable to locate libpam.])
|
||||
+ fi
|
||||
+ fi
|
||||
+ fi
|
||||
+ fi
|
||||
+ if test "$withpam" != no ; then
|
||||
+ AC_MSG_NOTICE([building with PAM support])
|
||||
+ AC_DEFINE(USE_PAM,1,[Define if Kerberos-aware tools should support PAM])
|
||||
+ AC_DEFINE_UNQUOTED(KSU_PAM_SERVICE,"$withksupamservice",
|
||||
+ [Define to the name of the PAM service name to be used by ksu.])
|
||||
+ PAM_LIBS="$LIBS"
|
||||
+ NON_PAM_MAN=".\\\" "
|
||||
+ PAM_MAN=
|
||||
+ else
|
||||
+ PAM_MAN=".\\\" "
|
||||
+ NON_PAM_MAN=
|
||||
+ fi
|
||||
+fi
|
||||
+LIBS="$old_LIBS"
|
||||
+AC_SUBST(PAM_LIBS)
|
||||
+AC_SUBST(PAM_MAN)
|
||||
+AC_SUBST(NON_PAM_MAN)
|
||||
+])dnl
|
||||
+
|
||||
diff --git a/src/clients/ksu/Makefile.in b/src/clients/ksu/Makefile.in
|
||||
index 8b4edce4d..9d58f29b5 100644
|
||||
--- a/src/clients/ksu/Makefile.in
|
||||
+++ b/src/clients/ksu/Makefile.in
|
||||
@@ -3,12 +3,14 @@ BUILDTOP=$(REL)..$(S)..
|
||||
DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/usr/local/sbin /usr/local/bin /sbin /bin /usr/sbin /usr/bin"'
|
||||
|
||||
KSU_LIBS=@KSU_LIBS@
|
||||
+PAM_LIBS=@PAM_LIBS@
|
||||
|
||||
SRCS = \
|
||||
$(srcdir)/krb_auth_su.c \
|
||||
$(srcdir)/ccache.c \
|
||||
$(srcdir)/authorization.c \
|
||||
$(srcdir)/main.c \
|
||||
+ $(srcdir)/pam.c \
|
||||
$(srcdir)/heuristic.c \
|
||||
$(srcdir)/xmalloc.c \
|
||||
$(srcdir)/setenv.c
|
||||
@@ -17,13 +19,17 @@ OBJS = \
|
||||
ccache.o \
|
||||
authorization.o \
|
||||
main.o \
|
||||
+ pam.o \
|
||||
heuristic.o \
|
||||
xmalloc.o @SETENVOBJ@
|
||||
|
||||
all: ksu
|
||||
|
||||
ksu: $(OBJS) $(KRB5_BASE_DEPLIBS)
|
||||
- $(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS)
|
||||
+ $(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS) $(PAM_LIBS)
|
||||
+
|
||||
+pam.o: pam.c
|
||||
+ $(CC) $(ALL_CFLAGS) -c $<
|
||||
|
||||
clean:
|
||||
$(RM) ksu
|
||||
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
|
||||
index af1286172..931f05404 100644
|
||||
--- a/src/clients/ksu/main.c
|
||||
+++ b/src/clients/ksu/main.c
|
||||
@@ -26,6 +26,7 @@
|
||||
* KSU was written by: Ari Medvinsky, ari@isi.edu
|
||||
*/
|
||||
|
||||
+#include "autoconf.h"
|
||||
#include "ksu.h"
|
||||
#include "adm_proto.h"
|
||||
#include <sys/types.h>
|
||||
@@ -33,6 +34,10 @@
|
||||
#include <signal.h>
|
||||
#include <grp.h>
|
||||
|
||||
+#ifdef USE_PAM
|
||||
+#include "pam.h"
|
||||
+#endif
|
||||
+
|
||||
/* globals */
|
||||
char * prog_name;
|
||||
int auth_debug =0;
|
||||
@@ -40,6 +45,7 @@ char k5login_path[MAXPATHLEN];
|
||||
char k5users_path[MAXPATHLEN];
|
||||
char * gb_err = NULL;
|
||||
int quiet = 0;
|
||||
+int force_fork = 0;
|
||||
/***********/
|
||||
|
||||
#define KS_TEMPORARY_CACHE "MEMORY:_ksu"
|
||||
@@ -536,6 +542,23 @@ main (argc, argv)
|
||||
prog_name,target_user,client_name,
|
||||
source_user,ontty());
|
||||
|
||||
+#ifdef USE_PAM
|
||||
+ if (appl_pam_enabled(ksu_context, "ksu")) {
|
||||
+ if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
|
||||
+ NULL, source_user,
|
||||
+ ttyname(STDERR_FILENO)) != 0) {
|
||||
+ fprintf(stderr, "Access denied for %s.\n", target_user);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ if (appl_pam_requires_chauthtok()) {
|
||||
+ fprintf(stderr, "Password change required for %s.\n",
|
||||
+ target_user);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ force_fork++;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
/* Run authorization as target.*/
|
||||
if (krb5_seteuid(target_uid)) {
|
||||
com_err(prog_name, errno, _("while switching to target for "
|
||||
@@ -596,6 +619,24 @@ main (argc, argv)
|
||||
|
||||
exit(1);
|
||||
}
|
||||
+#ifdef USE_PAM
|
||||
+ } else {
|
||||
+ /* we always do PAM account management, even for root */
|
||||
+ if (appl_pam_enabled(ksu_context, "ksu")) {
|
||||
+ if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
|
||||
+ NULL, source_user,
|
||||
+ ttyname(STDERR_FILENO)) != 0) {
|
||||
+ fprintf(stderr, "Access denied for %s.\n", target_user);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ if (appl_pam_requires_chauthtok()) {
|
||||
+ fprintf(stderr, "Password change required for %s.\n",
|
||||
+ target_user);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ force_fork++;
|
||||
+ }
|
||||
+#endif
|
||||
}
|
||||
|
||||
if( some_rest_copy){
|
||||
@@ -653,6 +694,30 @@ main (argc, argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
+#ifdef USE_PAM
|
||||
+ if (appl_pam_enabled(ksu_context, "ksu")) {
|
||||
+ if (appl_pam_session_open() != 0) {
|
||||
+ fprintf(stderr, "Error opening session for %s.\n", target_user);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+#ifdef DEBUG
|
||||
+ if (auth_debug){
|
||||
+ printf(" Opened PAM session.\n");
|
||||
+ }
|
||||
+#endif
|
||||
+ if (appl_pam_cred_init()) {
|
||||
+ fprintf(stderr, "Error initializing credentials for %s.\n",
|
||||
+ target_user);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+#ifdef DEBUG
|
||||
+ if (auth_debug){
|
||||
+ printf(" Initialized PAM credentials.\n");
|
||||
+ }
|
||||
+#endif
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
/* set permissions */
|
||||
if (setgid(target_pwd->pw_gid) < 0) {
|
||||
perror("ksu: setgid");
|
||||
@@ -750,7 +815,7 @@ main (argc, argv)
|
||||
fprintf(stderr, "program to be execed %s\n",params[0]);
|
||||
}
|
||||
|
||||
- if( keep_target_cache ) {
|
||||
+ if( keep_target_cache && !force_fork ) {
|
||||
execv(params[0], params);
|
||||
com_err(prog_name, errno, _("while trying to execv %s"), params[0]);
|
||||
sweep_up(ksu_context, cc_target);
|
||||
@@ -780,16 +845,35 @@ main (argc, argv)
|
||||
if (ret_pid == -1) {
|
||||
com_err(prog_name, errno, _("while calling waitpid"));
|
||||
}
|
||||
- sweep_up(ksu_context, cc_target);
|
||||
+ if( !keep_target_cache ) {
|
||||
+ sweep_up(ksu_context, cc_target);
|
||||
+ }
|
||||
exit (statusp);
|
||||
case -1:
|
||||
com_err(prog_name, errno, _("while trying to fork."));
|
||||
sweep_up(ksu_context, cc_target);
|
||||
exit (1);
|
||||
case 0:
|
||||
+#ifdef USE_PAM
|
||||
+ if (appl_pam_enabled(ksu_context, "ksu")) {
|
||||
+ if (appl_pam_setenv() != 0) {
|
||||
+ fprintf(stderr, "Error setting up environment for %s.\n",
|
||||
+ target_user);
|
||||
+ exit (1);
|
||||
+ }
|
||||
+#ifdef DEBUG
|
||||
+ if (auth_debug){
|
||||
+ printf(" Set up PAM environment.\n");
|
||||
+ }
|
||||
+#endif
|
||||
+ }
|
||||
+#endif
|
||||
execv(params[0], params);
|
||||
com_err(prog_name, errno, _("while trying to execv %s"),
|
||||
params[0]);
|
||||
+ if( keep_target_cache ) {
|
||||
+ sweep_up(ksu_context, cc_target);
|
||||
+ }
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
diff --git a/src/clients/ksu/pam.c b/src/clients/ksu/pam.c
|
||||
new file mode 100644
|
||||
index 000000000..cbfe48704
|
||||
--- /dev/null
|
||||
+++ b/src/clients/ksu/pam.c
|
||||
@@ -0,0 +1,389 @@
|
||||
+/*
|
||||
+ * src/clients/ksu/pam.c
|
||||
+ *
|
||||
+ * Copyright 2007,2009,2010 Red Hat, Inc.
|
||||
+ *
|
||||
+ * All Rights Reserved.
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are met:
|
||||
+ *
|
||||
+ * Redistributions of source code must retain the above copyright notice, this
|
||||
+ * list of conditions and the following disclaimer.
|
||||
+ *
|
||||
+ * Redistributions in binary form must reproduce the above copyright notice,
|
||||
+ * this list of conditions and the following disclaimer in the documentation
|
||||
+ * and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * Neither the name of Red Hat, Inc. nor the names of its contributors may be
|
||||
+ * used to endorse or promote products derived from this software without
|
||||
+ * specific prior written permission.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ *
|
||||
+ * Convenience wrappers for using PAM.
|
||||
+ */
|
||||
+
|
||||
+#include "autoconf.h"
|
||||
+#ifdef USE_PAM
|
||||
+#include <sys/types.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <unistd.h>
|
||||
+#include "k5-int.h"
|
||||
+#include "pam.h"
|
||||
+
|
||||
+#ifndef MAXPWSIZE
|
||||
+#define MAXPWSIZE 128
|
||||
+#endif
|
||||
+
|
||||
+static int appl_pam_started;
|
||||
+static pid_t appl_pam_starter = -1;
|
||||
+static int appl_pam_session_opened;
|
||||
+static int appl_pam_creds_initialized;
|
||||
+static int appl_pam_pwchange_required;
|
||||
+static pam_handle_t *appl_pamh;
|
||||
+static struct pam_conv appl_pam_conv;
|
||||
+static char *appl_pam_user;
|
||||
+struct appl_pam_non_interactive_args {
|
||||
+ const char *user;
|
||||
+ const char *password;
|
||||
+};
|
||||
+
|
||||
+int
|
||||
+appl_pam_enabled(krb5_context context, const char *section)
|
||||
+{
|
||||
+ int enabled = 1;
|
||||
+ if ((context != NULL) && (context->profile != NULL)) {
|
||||
+ if (profile_get_boolean(context->profile,
|
||||
+ section,
|
||||
+ USE_PAM_CONFIGURATION_KEYWORD,
|
||||
+ NULL,
|
||||
+ enabled, &enabled) != 0) {
|
||||
+ enabled = 1;
|
||||
+ }
|
||||
+ }
|
||||
+ return enabled;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+appl_pam_cleanup(void)
|
||||
+{
|
||||
+ if (getpid() != appl_pam_starter) {
|
||||
+ return;
|
||||
+ }
|
||||
+#ifdef DEBUG
|
||||
+ printf("Called to clean up PAM.\n");
|
||||
+#endif
|
||||
+ if (appl_pam_creds_initialized) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Deleting PAM credentials.\n");
|
||||
+#endif
|
||||
+ pam_setcred(appl_pamh, PAM_DELETE_CRED);
|
||||
+ appl_pam_creds_initialized = 0;
|
||||
+ }
|
||||
+ if (appl_pam_session_opened) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Closing PAM session.\n");
|
||||
+#endif
|
||||
+ pam_close_session(appl_pamh, 0);
|
||||
+ appl_pam_session_opened = 0;
|
||||
+ }
|
||||
+ appl_pam_pwchange_required = 0;
|
||||
+ if (appl_pam_started) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Shutting down PAM.\n");
|
||||
+#endif
|
||||
+ pam_end(appl_pamh, 0);
|
||||
+ appl_pam_started = 0;
|
||||
+ appl_pam_starter = -1;
|
||||
+ free(appl_pam_user);
|
||||
+ appl_pam_user = NULL;
|
||||
+ }
|
||||
+}
|
||||
+static int
|
||||
+appl_pam_interactive_converse(int num_msg, const struct pam_message **msg,
|
||||
+ struct pam_response **presp, void *appdata_ptr)
|
||||
+{
|
||||
+ const struct pam_message *message;
|
||||
+ struct pam_response *resp;
|
||||
+ int i, code;
|
||||
+ char *pwstring, pwbuf[MAXPWSIZE];
|
||||
+ unsigned int pwsize;
|
||||
+ resp = malloc(sizeof(struct pam_response) * num_msg);
|
||||
+ if (resp == NULL) {
|
||||
+ return PAM_BUF_ERR;
|
||||
+ }
|
||||
+ memset(resp, 0, sizeof(struct pam_response) * num_msg);
|
||||
+ code = PAM_SUCCESS;
|
||||
+ for (i = 0; i < num_msg; i++) {
|
||||
+ message = &(msg[0][i]); /* XXX */
|
||||
+ message = msg[i]; /* XXX */
|
||||
+ pwstring = NULL;
|
||||
+ switch (message->msg_style) {
|
||||
+ case PAM_TEXT_INFO:
|
||||
+ case PAM_ERROR_MSG:
|
||||
+ printf("[%s]\n", message->msg ? message->msg : "");
|
||||
+ fflush(stdout);
|
||||
+ resp[i].resp = NULL;
|
||||
+ resp[i].resp_retcode = PAM_SUCCESS;
|
||||
+ break;
|
||||
+ case PAM_PROMPT_ECHO_ON:
|
||||
+ case PAM_PROMPT_ECHO_OFF:
|
||||
+ if (message->msg_style == PAM_PROMPT_ECHO_ON) {
|
||||
+ if (fgets(pwbuf, sizeof(pwbuf),
|
||||
+ stdin) != NULL) {
|
||||
+ pwbuf[strcspn(pwbuf, "\r\n")] = '\0';
|
||||
+ pwstring = pwbuf;
|
||||
+ }
|
||||
+ } else {
|
||||
+ pwstring = getpass(message->msg ?
|
||||
+ message->msg :
|
||||
+ "");
|
||||
+ }
|
||||
+ if ((pwstring != NULL) && (pwstring[0] != '\0')) {
|
||||
+ pwsize = strlen(pwstring);
|
||||
+ resp[i].resp = malloc(pwsize + 1);
|
||||
+ if (resp[i].resp == NULL) {
|
||||
+ resp[i].resp_retcode = PAM_BUF_ERR;
|
||||
+ } else {
|
||||
+ memcpy(resp[i].resp, pwstring, pwsize);
|
||||
+ resp[i].resp[pwsize] = '\0';
|
||||
+ resp[i].resp_retcode = PAM_SUCCESS;
|
||||
+ }
|
||||
+ } else {
|
||||
+ resp[i].resp_retcode = PAM_CONV_ERR;
|
||||
+ code = PAM_CONV_ERR;
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ *presp = resp;
|
||||
+ return code;
|
||||
+}
|
||||
+static int
|
||||
+appl_pam_non_interactive_converse(int num_msg,
|
||||
+ const struct pam_message **msg,
|
||||
+ struct pam_response **presp,
|
||||
+ void *appdata_ptr)
|
||||
+{
|
||||
+ const struct pam_message *message;
|
||||
+ struct pam_response *resp;
|
||||
+ int i, code;
|
||||
+ unsigned int pwsize;
|
||||
+ struct appl_pam_non_interactive_args *args;
|
||||
+ const char *pwstring;
|
||||
+ resp = malloc(sizeof(struct pam_response) * num_msg);
|
||||
+ if (resp == NULL) {
|
||||
+ return PAM_BUF_ERR;
|
||||
+ }
|
||||
+ args = appdata_ptr;
|
||||
+ memset(resp, 0, sizeof(struct pam_response) * num_msg);
|
||||
+ code = PAM_SUCCESS;
|
||||
+ for (i = 0; i < num_msg; i++) {
|
||||
+ message = &((*msg)[i]);
|
||||
+ message = msg[i];
|
||||
+ pwstring = NULL;
|
||||
+ switch (message->msg_style) {
|
||||
+ case PAM_TEXT_INFO:
|
||||
+ case PAM_ERROR_MSG:
|
||||
+ break;
|
||||
+ case PAM_PROMPT_ECHO_ON:
|
||||
+ case PAM_PROMPT_ECHO_OFF:
|
||||
+ if (message->msg_style == PAM_PROMPT_ECHO_ON) {
|
||||
+ /* assume "user" */
|
||||
+ pwstring = args->user;
|
||||
+ } else {
|
||||
+ /* assume "password" */
|
||||
+ pwstring = args->password;
|
||||
+ }
|
||||
+ if ((pwstring != NULL) && (pwstring[0] != '\0')) {
|
||||
+ pwsize = strlen(pwstring);
|
||||
+ resp[i].resp = malloc(pwsize + 1);
|
||||
+ if (resp[i].resp == NULL) {
|
||||
+ resp[i].resp_retcode = PAM_BUF_ERR;
|
||||
+ } else {
|
||||
+ memcpy(resp[i].resp, pwstring, pwsize);
|
||||
+ resp[i].resp[pwsize] = '\0';
|
||||
+ resp[i].resp_retcode = PAM_SUCCESS;
|
||||
+ }
|
||||
+ } else {
|
||||
+ resp[i].resp_retcode = PAM_CONV_ERR;
|
||||
+ code = PAM_CONV_ERR;
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ *presp = resp;
|
||||
+ return code;
|
||||
+}
|
||||
+static int
|
||||
+appl_pam_start(const char *service, int interactive,
|
||||
+ const char *login_username,
|
||||
+ const char *non_interactive_password,
|
||||
+ const char *hostname,
|
||||
+ const char *ruser,
|
||||
+ const char *tty)
|
||||
+{
|
||||
+ static int exit_handler_registered;
|
||||
+ static struct appl_pam_non_interactive_args args;
|
||||
+ int ret = 0;
|
||||
+ if (appl_pam_started &&
|
||||
+ (strcmp(login_username, appl_pam_user) != 0)) {
|
||||
+ appl_pam_cleanup();
|
||||
+ appl_pam_user = NULL;
|
||||
+ }
|
||||
+ if (!appl_pam_started) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Starting PAM up (service=\"%s\",user=\"%s\").\n",
|
||||
+ service, login_username);
|
||||
+#endif
|
||||
+ memset(&appl_pam_conv, 0, sizeof(appl_pam_conv));
|
||||
+ appl_pam_conv.conv = interactive ?
|
||||
+ &appl_pam_interactive_converse :
|
||||
+ &appl_pam_non_interactive_converse;
|
||||
+ memset(&args, 0, sizeof(args));
|
||||
+ args.user = strdup(login_username);
|
||||
+ args.password = non_interactive_password ?
|
||||
+ strdup(non_interactive_password) :
|
||||
+ NULL;
|
||||
+ appl_pam_conv.appdata_ptr = &args;
|
||||
+ ret = pam_start(service, login_username,
|
||||
+ &appl_pam_conv, &appl_pamh);
|
||||
+ if (ret == 0) {
|
||||
+ if (hostname != NULL) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Setting PAM_RHOST to \"%s\".\n", hostname);
|
||||
+#endif
|
||||
+ pam_set_item(appl_pamh, PAM_RHOST, hostname);
|
||||
+ }
|
||||
+ if (ruser != NULL) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Setting PAM_RUSER to \"%s\".\n", ruser);
|
||||
+#endif
|
||||
+ pam_set_item(appl_pamh, PAM_RUSER, ruser);
|
||||
+ }
|
||||
+ if (tty != NULL) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Setting PAM_TTY to \"%s\".\n", tty);
|
||||
+#endif
|
||||
+ pam_set_item(appl_pamh, PAM_TTY, tty);
|
||||
+ }
|
||||
+ if (!exit_handler_registered &&
|
||||
+ (atexit(appl_pam_cleanup) != 0)) {
|
||||
+ pam_end(appl_pamh, 0);
|
||||
+ appl_pamh = NULL;
|
||||
+ ret = -1;
|
||||
+ } else {
|
||||
+ appl_pam_started = 1;
|
||||
+ appl_pam_starter = getpid();
|
||||
+ appl_pam_user = strdup(login_username);
|
||||
+ exit_handler_registered = 1;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+int
|
||||
+appl_pam_acct_mgmt(const char *service, int interactive,
|
||||
+ const char *login_username,
|
||||
+ const char *non_interactive_password,
|
||||
+ const char *hostname,
|
||||
+ const char *ruser,
|
||||
+ const char *tty)
|
||||
+{
|
||||
+ int ret;
|
||||
+ appl_pam_pwchange_required = 0;
|
||||
+ ret = appl_pam_start(service, interactive, login_username,
|
||||
+ non_interactive_password, hostname, ruser, tty);
|
||||
+ if (ret == 0) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Calling pam_acct_mgmt().\n");
|
||||
+#endif
|
||||
+ ret = pam_acct_mgmt(appl_pamh, 0);
|
||||
+ switch (ret) {
|
||||
+ case PAM_IGNORE:
|
||||
+ ret = 0;
|
||||
+ break;
|
||||
+ case PAM_NEW_AUTHTOK_REQD:
|
||||
+ appl_pam_pwchange_required = 1;
|
||||
+ ret = 0;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+int
|
||||
+appl_pam_requires_chauthtok(void)
|
||||
+{
|
||||
+ return appl_pam_pwchange_required;
|
||||
+}
|
||||
+int
|
||||
+appl_pam_session_open(void)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ if (appl_pam_started) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Opening PAM session.\n");
|
||||
+#endif
|
||||
+ ret = pam_open_session(appl_pamh, 0);
|
||||
+ if (ret == 0) {
|
||||
+ appl_pam_session_opened = 1;
|
||||
+ }
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+int
|
||||
+appl_pam_setenv(void)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+#ifdef HAVE_PAM_GETENVLIST
|
||||
+#ifdef HAVE_PUTENV
|
||||
+ int i;
|
||||
+ char **list;
|
||||
+ if (appl_pam_started) {
|
||||
+ list = pam_getenvlist(appl_pamh);
|
||||
+ for (i = 0; ((list != NULL) && (list[i] != NULL)); i++) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Setting \"%s\" in environment.\n", list[i]);
|
||||
+#endif
|
||||
+ putenv(list[i]);
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+#endif
|
||||
+ return ret;
|
||||
+}
|
||||
+int
|
||||
+appl_pam_cred_init(void)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ if (appl_pam_started) {
|
||||
+#ifdef DEBUG
|
||||
+ printf("Initializing PAM credentials.\n");
|
||||
+#endif
|
||||
+ ret = pam_setcred(appl_pamh, PAM_ESTABLISH_CRED);
|
||||
+ if (ret == 0) {
|
||||
+ appl_pam_creds_initialized = 1;
|
||||
+ }
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+#endif
|
||||
diff --git a/src/clients/ksu/pam.h b/src/clients/ksu/pam.h
|
||||
new file mode 100644
|
||||
index 000000000..0ab76569c
|
||||
--- /dev/null
|
||||
+++ b/src/clients/ksu/pam.h
|
||||
@@ -0,0 +1,57 @@
|
||||
+/*
|
||||
+ * src/clients/ksu/pam.h
|
||||
+ *
|
||||
+ * Copyright 2007,2009,2010 Red Hat, Inc.
|
||||
+ *
|
||||
+ * All Rights Reserved.
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are met:
|
||||
+ *
|
||||
+ * Redistributions of source code must retain the above copyright notice, this
|
||||
+ * list of conditions and the following disclaimer.
|
||||
+ *
|
||||
+ * Redistributions in binary form must reproduce the above copyright notice,
|
||||
+ * this list of conditions and the following disclaimer in the documentation
|
||||
+ * and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * Neither the name of Red Hat, Inc. nor the names of its contributors may be
|
||||
+ * used to endorse or promote products derived from this software without
|
||||
+ * specific prior written permission.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ *
|
||||
+ * Convenience wrappers for using PAM.
|
||||
+ */
|
||||
+
|
||||
+#include <krb5.h>
|
||||
+#ifdef HAVE_SECURITY_PAM_APPL_H
|
||||
+#include <security/pam_appl.h>
|
||||
+#endif
|
||||
+
|
||||
+#define USE_PAM_CONFIGURATION_KEYWORD "use_pam"
|
||||
+
|
||||
+#ifdef USE_PAM
|
||||
+int appl_pam_enabled(krb5_context context, const char *section);
|
||||
+int appl_pam_acct_mgmt(const char *service, int interactive,
|
||||
+ const char *local_username,
|
||||
+ const char *non_interactive_password,
|
||||
+ const char *hostname,
|
||||
+ const char *ruser,
|
||||
+ const char *tty);
|
||||
+int appl_pam_requires_chauthtok(void);
|
||||
+int appl_pam_session_open(void);
|
||||
+int appl_pam_setenv(void);
|
||||
+int appl_pam_cred_init(void);
|
||||
+void appl_pam_cleanup(void);
|
||||
+#endif
|
||||
diff --git a/src/configure.ac b/src/configure.ac
|
||||
index 4eb080784..693f76a81 100644
|
||||
--- a/src/configure.ac
|
||||
+++ b/src/configure.ac
|
||||
@@ -1389,6 +1389,8 @@ AC_SUBST([VERTO_VERSION])
|
||||
|
||||
AC_PATH_PROG(GROFF, groff)
|
||||
|
||||
+KRB5_WITH_PAM
|
||||
+
|
||||
# Make localedir work in autoconf 2.5x.
|
||||
if test "${localedir+set}" != set; then
|
||||
localedir='$(datadir)/locale'
|
24
SOURCES/downstream-netlib-and-dns.patch
Normal file
24
SOURCES/downstream-netlib-and-dns.patch
Normal file
@ -0,0 +1,24 @@
|
||||
From ad123366e5fb2694cf6d9f4f292a001a761b78fa Mon Sep 17 00:00:00 2001
|
||||
From: Robbie Harwood <rharwood@redhat.com>
|
||||
Date: Tue, 23 Aug 2016 16:46:21 -0400
|
||||
Subject: [PATCH] [downstream] netlib and dns
|
||||
|
||||
We want to be able to use --with-netlib and --enable-dns at the same time.
|
||||
|
||||
Last-updated: krb5-1.3.1
|
||||
---
|
||||
src/aclocal.m4 | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/src/aclocal.m4 b/src/aclocal.m4
|
||||
index 5afb96e58..4a4d460e3 100644
|
||||
--- a/src/aclocal.m4
|
||||
+++ b/src/aclocal.m4
|
||||
@@ -718,6 +718,7 @@ AC_HELP_STRING([--with-netlib=LIBS], use user defined resolver library),
|
||||
LIBS="$LIBS $withval"
|
||||
AC_MSG_RESULT("netlib will use \'$withval\'")
|
||||
fi
|
||||
+ KRB5_AC_ENABLE_DNS
|
||||
],dnl
|
||||
[AC_LIBRARY_NET]
|
||||
)])dnl
|
1
SOURCES/kadm5.acl
Normal file
1
SOURCES/kadm5.acl
Normal file
@ -0,0 +1 @@
|
||||
*/admin@EXAMPLE.COM *
|
15
SOURCES/kadmin.service
Normal file
15
SOURCES/kadmin.service
Normal file
@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=Kerberos 5 Password-changing and Administration
|
||||
Wants=network-online.target
|
||||
After=syslog.target network.target network-online.target
|
||||
AssertPathExists=!/var/kerberos/krb5kdc/kpropd.acl
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
PIDFile=/run/kadmind.pid
|
||||
EnvironmentFile=-/etc/sysconfig/kadmin
|
||||
ExecStart=/usr/sbin/kadmind -P /run/kadmind.pid $KADMIND_ARGS
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
1
SOURCES/kadmin.sysconfig
Normal file
1
SOURCES/kadmin.sysconfig
Normal file
@ -0,0 +1 @@
|
||||
KADMIND_ARGS=
|
9
SOURCES/kadmind.logrotate
Normal file
9
SOURCES/kadmind.logrotate
Normal file
@ -0,0 +1,9 @@
|
||||
/var/log/kadmind.log {
|
||||
missingok
|
||||
notifempty
|
||||
monthly
|
||||
rotate 12
|
||||
postrotate
|
||||
systemctl reload kadmin.service || true
|
||||
endscript
|
||||
}
|
14
SOURCES/kdc.conf
Normal file
14
SOURCES/kdc.conf
Normal file
@ -0,0 +1,14 @@
|
||||
[kdcdefaults]
|
||||
kdc_ports = 88
|
||||
kdc_tcp_ports = 88
|
||||
spake_preauth_kdc_challenge = edwards25519
|
||||
|
||||
[realms]
|
||||
EXAMPLE.COM = {
|
||||
#master_key_type = aes256-cts
|
||||
acl_file = /var/kerberos/krb5kdc/kadm5.acl
|
||||
dict_file = /usr/share/dict/words
|
||||
default_principal_flags = +preauth
|
||||
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
|
||||
supported_enctypes = aes256-cts:normal aes128-cts:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal
|
||||
}
|
13
SOURCES/kprop.service
Normal file
13
SOURCES/kprop.service
Normal file
@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Kerberos 5 Propagation
|
||||
Wants=network-online.target
|
||||
After=syslog.target network.target network-online.target
|
||||
AssertPathExists=/var/kerberos/krb5kdc/kpropd.acl
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
EnvironmentFile=-/etc/sysconfig/kprop
|
||||
ExecStart=/usr/sbin/kpropd $KPROPD_ARGS
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
1
SOURCES/kprop.sysconfig
Normal file
1
SOURCES/kprop.sysconfig
Normal file
@ -0,0 +1 @@
|
||||
KPROPD_ARGS=
|
16
SOURCES/krb5-1.19.1.tar.gz.asc
Normal file
16
SOURCES/krb5-1.19.1.tar.gz.asc
Normal file
@ -0,0 +1,16 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQIzBAABCgAdFiEExEk8tzn0qJ+YUsvCDLoIV1+Dct8FAmAuntAACgkQDLoIV1+D
|
||||
ct8TIhAArFittFBcz4ZfMxqhHVGdK6kOeQXrrV27d3FW6y28BvS7yHJ8CkyK+I3g
|
||||
4rsaaf7srkH8jaiCjmjHC2rWJIuceOwkD4GRqXtb2CiqKxXI9eZ+g9ipB7DGKixg
|
||||
+1nki7mOhd3oaeUkCRFXgyiOqSE/ird7/itLYzEoAroLpTazNp6Kk4gXmhJIENlq
|
||||
dj1God+JxhuwzzWZRdsy2SyvMQPQMOTIilsXRboObZFvPrhZKkJmgNm+RzU/YRSg
|
||||
/1Po7takBXq8qhgnwPHTnTPb+BYRdrqQc/a2WcmEdgbzeMpijNmkFsgAFeKDijSz
|
||||
1nmFO4SQd/rAfgUovkDd+GMAYZ6DCLFqoI/WeKOgCrRMxJMMRbLlr48bTvMwjuIl
|
||||
xE5gy8h2Iju/UP1lxz8KheCm/FyNzNw4pe74zbGgK5fdiEQ8xNlKZOs9LRrtvyfL
|
||||
j1G+IX6cK+5yTo/NceYjnHVAatbuW6C6xJmsIQ1GYdMPvto7Wctq/4/BmwxqgFAJ
|
||||
HCPuQgAGi875JpPYvi/c3tioRiIPwOz54CXCrcFyKELvgHi6lGN6MRNSzAP4QdA0
|
||||
HlXZQ4/4NFOJxjLGu9ZXKUbYPaGizhI+ayzg5/RJLHPIgW7yLvwFqkBIa1xs26bA
|
||||
xiP5JKuDC4mqDPwVjwpufkUBH6SoBFnbiIWEYSKVPLJFw+Dbhv0=
|
||||
=PP6r
|
||||
-----END PGP SIGNATURE-----
|
1
SOURCES/krb5-krb5kdc.conf
Normal file
1
SOURCES/krb5-krb5kdc.conf
Normal file
@ -0,0 +1 @@
|
||||
d /run/krb5kdc 0755 root root
|
30
SOURCES/krb5.conf
Normal file
30
SOURCES/krb5.conf
Normal file
@ -0,0 +1,30 @@
|
||||
# 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]
|
||||
dns_lookup_realm = false
|
||||
ticket_lifetime = 24h
|
||||
renew_lifetime = 7d
|
||||
forwardable = true
|
||||
rdns = false
|
||||
pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt
|
||||
spake_preauth_groups = edwards25519
|
||||
dns_canonicalize_hostname = fallback
|
||||
qualify_shortname = ""
|
||||
# default_realm = EXAMPLE.COM
|
||||
|
||||
[realms]
|
||||
# EXAMPLE.COM = {
|
||||
# kdc = kerberos.example.com
|
||||
# admin_server = kerberos.example.com
|
||||
# }
|
||||
|
||||
[domain_realm]
|
||||
# .example.com = EXAMPLE.COM
|
||||
# example.com = EXAMPLE.COM
|
9
SOURCES/krb5kdc.logrotate
Normal file
9
SOURCES/krb5kdc.logrotate
Normal file
@ -0,0 +1,9 @@
|
||||
/var/log/krb5kdc.log {
|
||||
missingok
|
||||
notifempty
|
||||
monthly
|
||||
rotate 12
|
||||
postrotate
|
||||
systemctl reload krb5kdc.service || true
|
||||
endscript
|
||||
}
|
14
SOURCES/krb5kdc.service
Normal file
14
SOURCES/krb5kdc.service
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Kerberos 5 KDC
|
||||
Wants=network-online.target
|
||||
After=syslog.target network.target network-online.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
PIDFile=/run/krb5kdc.pid
|
||||
EnvironmentFile=-/etc/sysconfig/krb5kdc
|
||||
ExecStart=/usr/sbin/krb5kdc -P /run/krb5kdc.pid $KRB5KDC_ARGS
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
1
SOURCES/krb5kdc.sysconfig
Normal file
1
SOURCES/krb5kdc.sysconfig
Normal file
@ -0,0 +1 @@
|
||||
KRB5KDC_ARGS=
|
4
SOURCES/ksu.pamd
Normal file
4
SOURCES/ksu.pamd
Normal file
@ -0,0 +1,4 @@
|
||||
#%PAM-1.0
|
||||
auth include su
|
||||
account include su
|
||||
session include su
|
4107
SPECS/krb5.spec
Normal file
4107
SPECS/krb5.spec
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user