diff --git a/SOURCES/Add-KDC-policy-pluggable-interface.patch b/SOURCES/Add-KDC-policy-pluggable-interface.patch new file mode 100644 index 0000000..19cb799 --- /dev/null +++ b/SOURCES/Add-KDC-policy-pluggable-interface.patch @@ -0,0 +1,995 @@ +From f12b57979012f93b339982ba335093d7c0d364f7 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 27 Jun 2017 17:15:39 -0400 +Subject: [PATCH] Add KDC policy pluggable interface + +Add the header include/krb5/kdcpolicy_plugin.h, defining a pluggable +interface for modules to deny AS and TGS requests and set maximum +ticket lifetimes. This interface replaces the policy.c stub functions. + +Add check_kdcpolicy_as() and check_kdcpolicy_tgs() as entry functions. +Call them after auth indicators and ticket lifetimes have been +determined. + +Add a test module and a test script with basic kdcpolicy tests. Add +plugin interface documentation in doc/plugindev/policy.rst. + +Also authored by Matt Rogers . + +ticket: 8606 (new) +(cherry picked from commit d0969f6a8170344031ef58fd2a161190f1edfb96) +[rharwood@redhat.com: mention but do not use kadm_auth] +Signed-off-by: Robbie Harwood +--- + doc/plugindev/index.rst | 1 + + doc/plugindev/kdcpolicy.rst | 24 +++ + src/Makefile.in | 1 + + src/configure.in | 1 + + src/include/Makefile.in | 1 + + src/include/k5-int.h | 4 +- + src/include/k5-trace.h | 5 + + src/include/krb5/kdcpolicy_plugin.h | 128 ++++++++++++ + src/kdc/do_as_req.c | 7 + + src/kdc/do_tgs_req.c | 6 + + src/kdc/kdc_util.c | 7 - + src/kdc/kdc_util.h | 11 - + src/kdc/main.c | 8 + + src/kdc/policy.c | 267 +++++++++++++++++++++---- + src/kdc/policy.h | 19 +- + src/kdc/tgs_policy.c | 6 - + src/lib/krb5/krb/plugin.c | 4 +- + src/plugins/kdcpolicy/test/Makefile.in | 20 ++ + src/plugins/kdcpolicy/test/deps | 0 + src/plugins/kdcpolicy/test/main.c | 111 ++++++++++ + src/plugins/kdcpolicy/test/policy_test.exports | 1 + + src/tests/Makefile.in | 1 + + src/tests/t_kdcpolicy.py | 57 ++++++ + 23 files changed, 616 insertions(+), 74 deletions(-) + create mode 100644 doc/plugindev/kdcpolicy.rst + create mode 100644 src/include/krb5/kdcpolicy_plugin.h + create mode 100644 src/plugins/kdcpolicy/test/Makefile.in + create mode 100644 src/plugins/kdcpolicy/test/deps + create mode 100644 src/plugins/kdcpolicy/test/main.c + create mode 100644 src/plugins/kdcpolicy/test/policy_test.exports + create mode 100644 src/tests/t_kdcpolicy.py + +diff --git a/doc/plugindev/index.rst b/doc/plugindev/index.rst +index 67dbc2790..0a012b82b 100644 +--- a/doc/plugindev/index.rst ++++ b/doc/plugindev/index.rst +@@ -32,5 +32,6 @@ Contents + gssapi.rst + internal.rst + certauth.rst ++ kdcpolicy.rst + + .. TODO: GSSAPI mechanism plugins +diff --git a/doc/plugindev/kdcpolicy.rst b/doc/plugindev/kdcpolicy.rst +new file mode 100644 +index 000000000..74f21f08f +--- /dev/null ++++ b/doc/plugindev/kdcpolicy.rst +@@ -0,0 +1,24 @@ ++.. _kdcpolicy_plugin: ++ ++KDC policy interface (kdcpolicy) ++================================ ++ ++The kdcpolicy interface was first introduced in release 1.16. It ++allows modules to veto otherwise valid AS and TGS requests or restrict ++the lifetime and renew time of the resulting ticket. For a detailed ++description of the kdcpolicy interface, see the header file ++````. ++ ++The optional **check_as** and **check_tgs** functions allow the module ++to perform access control. Additionally, a module can create and ++destroy module data with the **init** and **fini** methods. Module ++data objects last for the lifetime of the KDC process, and are ++provided to all other methods. The data has the type ++krb5_kdcpolicy_moddata, which should be cast to the appropriate ++internal type. ++ ++kdcpolicy modules can optionally inspect principal entries. To do ++this, the module must also include ```` to gain access to the ++principal entry structure definition. As the KDB interface is ++explicitly not as stable as other public interfaces, modules which do ++this may not retain compatibility across releases. +diff --git a/src/Makefile.in b/src/Makefile.in +index ad8565056..e47bddcb1 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -21,6 +21,7 @@ SUBDIRS=util include lib \ + plugins/kdb/db2 \ + @ldap_plugin_dir@ \ + plugins/kdb/test \ ++ plugins/kdcpolicy/test \ + plugins/preauth/otp \ + plugins/preauth/pkinit \ + plugins/preauth/test \ +diff --git a/src/configure.in b/src/configure.in +index 4ae2c07d5..ee1983043 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -1470,6 +1470,7 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test + plugins/kdb/db2/libdb2/recno + plugins/kdb/db2/libdb2/test + plugins/kdb/test ++ plugins/kdcpolicy/test + plugins/preauth/otp + plugins/preauth/test + plugins/authdata/greet_client +diff --git a/src/include/Makefile.in b/src/include/Makefile.in +index 0239338a1..6a3fa8242 100644 +--- a/src/include/Makefile.in ++++ b/src/include/Makefile.in +@@ -144,6 +144,7 @@ install-headers-unix install: krb5/krb5.h profile.h + $(INSTALL_DATA) $(srcdir)/krb5/ccselect_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)ccselect_plugin.h + $(INSTALL_DATA) $(srcdir)/krb5/clpreauth_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)clpreauth_plugin.h + $(INSTALL_DATA) $(srcdir)/krb5/hostrealm_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)hostrealm_plugin.h ++ $(INSTALL_DATA) $(srcdir)/krb5/kdcpolicy_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)kdcpolicy_plugin.h + $(INSTALL_DATA) $(srcdir)/krb5/kdcpreauth_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)kdcpreauth_plugin.h + $(INSTALL_DATA) $(srcdir)/krb5/localauth_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)localauth_plugin.h + $(INSTALL_DATA) $(srcdir)/krb5/locate_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)locate_plugin.h +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index ed9c7bf75..39ffb9568 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -1157,7 +1157,9 @@ struct plugin_interface { + #define PLUGIN_INTERFACE_TLS 8 + #define PLUGIN_INTERFACE_KDCAUTHDATA 9 + #define PLUGIN_INTERFACE_CERTAUTH 10 +-#define PLUGIN_NUM_INTERFACES 11 ++#define PLUGIN_INTERFACE_KADM5_AUTH 11 ++#define PLUGIN_INTERFACE_KDCPOLICY 12 ++#define PLUGIN_NUM_INTERFACES 13 + + /* Retrieve the plugin module of type interface_id and name modname, + * storing the result into module. */ +diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h +index c75e264e0..2885408a2 100644 +--- a/src/include/k5-trace.h ++++ b/src/include/k5-trace.h +@@ -454,4 +454,9 @@ void krb5int_trace(krb5_context context, const char *fmt, ...); + #define TRACE_GET_CRED_VIA_TKT_EXT_RETURN(c, ret) \ + TRACE(c, "Got cred; {kerr}", ret) + ++#define TRACE_KDCPOLICY_VTINIT_FAIL(c, ret) \ ++ TRACE(c, "KDC policy module failed to init vtable: {kerr}", ret) ++#define TRACE_KDCPOLICY_INIT_SKIP(c, name) \ ++ TRACE(c, "kadm5_auth module {str} declined to initialize", name) ++ + #endif /* K5_TRACE_H */ +diff --git a/src/include/krb5/kdcpolicy_plugin.h b/src/include/krb5/kdcpolicy_plugin.h +new file mode 100644 +index 000000000..c7592c5db +--- /dev/null ++++ b/src/include/krb5/kdcpolicy_plugin.h +@@ -0,0 +1,128 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* include/krb5/kdcpolicy_plugin.h - KDC policy plugin interface */ ++/* ++ * Copyright (C) 2017 by Red Hat, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * Declarations for kdcpolicy plugin module implementors. ++ * ++ * The kdcpolicy pluggable interface currently has only one supported major ++ * version, which is 1. Major version 1 has a current minor version number of ++ * 1. ++ * ++ * kdcpolicy plugin modules should define a function named ++ * kdcpolicy__initvt, matching the signature: ++ * ++ * krb5_error_code ++ * kdcpolicy_modname_initvt(krb5_context context, int maj_ver, int min_ver, ++ * krb5_plugin_vtable vtable); ++ * ++ * The initvt function should: ++ * ++ * - Check that the supplied maj_ver number is supported by the module, or ++ * return KRB5_PLUGIN_VER_NOTSUPP if it is not. ++ * ++ * - Cast the vtable pointer as appropriate for maj_ver: ++ * maj_ver == 1: Cast to krb5_kdcpolicy_vtable ++ * ++ * - Initialize the methods of the vtable, stopping as appropriate for the ++ * supplied min_ver. Optional methods may be left uninitialized. ++ * ++ * Memory for the vtable is allocated by the caller, not by the module. ++ */ ++ ++#ifndef KRB5_POLICY_PLUGIN_H ++#define KRB5_POLICY_PLUGIN_H ++ ++#include ++ ++/* Abstract module datatype. */ ++typedef struct krb5_kdcpolicy_moddata_st *krb5_kdcpolicy_moddata; ++ ++/* A module can optionally include kdb.h to inspect principal entries when ++ * authorizing requests. */ ++struct _krb5_db_entry_new; ++ ++/* ++ * Optional: Initialize module data. Return 0 on success, ++ * KRB5_PLUGIN_NO_HANDLE if the module is inoperable (due to configuration, for ++ * example), and any other error code to abort KDC startup. Optionally set ++ * *data_out to a module data object to be passed to future calls. ++ */ ++typedef krb5_error_code ++(*krb5_kdcpolicy_init_fn)(krb5_context context, ++ krb5_kdcpolicy_moddata *data_out); ++ ++/* Optional: Clean up module data. */ ++typedef krb5_error_code ++(*krb5_kdcpolicy_fini_fn)(krb5_context context, ++ krb5_kdcpolicy_moddata moddata); ++ ++/* ++ * Optional: return an error code and set status to an appropriate string ++ * literal to deny an AS request; otherwise return 0. lifetime_out, if set, ++ * restricts the ticket lifetime. renew_lifetime_out, if set, restricts the ++ * ticket renewable lifetime. ++ */ ++typedef krb5_error_code ++(*krb5_kdcpolicy_check_as_fn)(krb5_context context, ++ krb5_kdcpolicy_moddata moddata, ++ const krb5_kdc_req *request, ++ const struct _krb5_db_entry_new *client, ++ const struct _krb5_db_entry_new *server, ++ const char *const *auth_indicators, ++ const char **status, krb5_deltat *lifetime_out, ++ krb5_deltat *renew_lifetime_out); ++ ++/* ++ * Optional: return an error code and set status to an appropriate string ++ * literal to deny a TGS request; otherwise return 0. lifetime_out, if set, ++ * restricts the ticket lifetime. renew_lifetime_out, if set, restricts the ++ * ticket renewable lifetime. ++ */ ++typedef krb5_error_code ++(*krb5_kdcpolicy_check_tgs_fn)(krb5_context context, ++ krb5_kdcpolicy_moddata moddata, ++ const krb5_kdc_req *request, ++ const struct _krb5_db_entry_new *server, ++ const krb5_ticket *ticket, ++ const char *const *auth_indicators, ++ const char **status, krb5_deltat *lifetime_out, ++ krb5_deltat *renew_lifetime_out); ++ ++typedef struct krb5_kdcpolicy_vtable_st { ++ const char *name; ++ krb5_kdcpolicy_init_fn init; ++ krb5_kdcpolicy_fini_fn fini; ++ krb5_kdcpolicy_check_as_fn check_as; ++ krb5_kdcpolicy_check_tgs_fn check_tgs; ++} *krb5_kdcpolicy_vtable; ++ ++#endif /* KRB5_POLICY_PLUGIN_H */ +diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c +index 59a39cd30..241b05b40 100644 +--- a/src/kdc/do_as_req.c ++++ b/src/kdc/do_as_req.c +@@ -207,6 +207,13 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + + state->ticket_reply.enc_part2 = &state->enc_tkt_reply; + ++ errcode = check_kdcpolicy_as(kdc_context, state->request, state->client, ++ state->server, state->auth_indicators, ++ state->kdc_time, &state->enc_tkt_reply.times, ++ &state->status); ++ if (errcode) ++ goto egress; ++ + /* + * Find the server key + */ +diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c +index aacd2f20d..4c722a4a3 100644 +--- a/src/kdc/do_tgs_req.c ++++ b/src/kdc/do_tgs_req.c +@@ -518,6 +518,12 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + kdc_get_ticket_renewtime(kdc_active_realm, request, header_enc_tkt, client, + server, &enc_tkt_reply); + ++ errcode = check_kdcpolicy_tgs(kdc_context, request, server, header_ticket, ++ auth_indicators, kdc_time, ++ &enc_tkt_reply.times, &status); ++ if (errcode) ++ goto cleanup; ++ + /* + * Set authtime to be the same as header or evidence ticket's + */ +diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c +index 778a629e5..8cbdf2c5b 100644 +--- a/src/kdc/kdc_util.c ++++ b/src/kdc/kdc_util.c +@@ -642,7 +642,6 @@ validate_as_request(kdc_realm_t *kdc_active_realm, + krb5_db_entry server, krb5_timestamp kdc_time, + const char **status, krb5_pa_data ***e_data) + { +- int errcode; + krb5_error_code ret; + + /* +@@ -750,12 +749,6 @@ validate_as_request(kdc_realm_t *kdc_active_realm, + if (ret && ret != KRB5_PLUGIN_OP_NOTSUPP) + return errcode_to_protocol(ret); + +- /* Check against local policy. */ +- errcode = against_local_policy_as(request, client, server, +- kdc_time, status, e_data); +- if (errcode) +- return errcode; +- + return 0; + } + +diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h +index 672f94380..dcedfd538 100644 +--- a/src/kdc/kdc_util.h ++++ b/src/kdc/kdc_util.h +@@ -166,17 +166,6 @@ kdc_err(krb5_context call_context, errcode_t code, const char *fmt, ...) + #endif + ; + +-/* policy.c */ +-int +-against_local_policy_as (krb5_kdc_req *, krb5_db_entry, +- krb5_db_entry, krb5_timestamp, +- const char **, krb5_pa_data ***); +- +-int +-against_local_policy_tgs (krb5_kdc_req *, krb5_db_entry, +- krb5_ticket *, const char **, +- krb5_pa_data ***); +- + /* kdc_preauth.c */ + krb5_boolean + enctype_requires_etype_info_2(krb5_enctype enctype); +diff --git a/src/kdc/main.c b/src/kdc/main.c +index a4dffb29a..ccac3a759 100644 +--- a/src/kdc/main.c ++++ b/src/kdc/main.c +@@ -31,6 +31,7 @@ + #include "kdc_util.h" + #include "kdc_audit.h" + #include "extern.h" ++#include "policy.h" + #include "kdc5_err.h" + #include "kdb_kt.h" + #include "net-server.h" +@@ -986,6 +987,12 @@ int main(int argc, char **argv) + + load_preauth_plugins(&shandle, kcontext, ctx); + load_authdata_plugins(kcontext); ++ retval = load_kdcpolicy_plugins(kcontext); ++ if (retval) { ++ kdc_err(kcontext, retval, _("while loading KDC policy plugin")); ++ finish_realms(); ++ return 1; ++ } + + retval = setup_sam(); + if (retval) { +@@ -1068,6 +1075,7 @@ int main(int argc, char **argv) + krb5_klog_syslog(LOG_INFO, _("shutting down")); + unload_preauth_plugins(kcontext); + unload_authdata_plugins(kcontext); ++ unload_kdcpolicy_plugins(kcontext); + unload_audit_modules(kcontext); + krb5_klog_close(kcontext); + finish_realms(); +diff --git a/src/kdc/policy.c b/src/kdc/policy.c +index 6cba4303f..e49644e06 100644 +--- a/src/kdc/policy.c ++++ b/src/kdc/policy.c +@@ -1,67 +1,246 @@ + /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ + /* kdc/policy.c - Policy decision routines for KDC */ + /* +- * Copyright 1990 by the Massachusetts Institute of Technology. ++ * Copyright (C) 2017 by Red Hat, Inc. ++ * All rights reserved. + * +- * Export of this software from the United States of America may +- * require a specific license from the United States Government. +- * It is the responsibility of any person or organization contemplating +- * export to obtain such a license before exporting. ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: + * +- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +- * distribute this software and its documentation for any purpose and +- * without fee is hereby granted, provided that the above copyright +- * notice appear in all copies and that both that copyright notice and +- * this permission notice appear in supporting documentation, and that +- * the name of M.I.T. not be used in advertising or publicity pertaining +- * to distribution of the software without specific, written prior +- * permission. Furthermore if you modify this software you must label +- * your software as modified software and not distribute it in such a +- * fashion that it might be confused with the original M.I.T. software. +- * M.I.T. makes no representations about the suitability of +- * this software for any purpose. It is provided "as is" without express +- * or implied warranty. ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include "k5-int.h" + #include "kdc_util.h" + #include "extern.h" ++#include "policy.h" ++#include "adm_proto.h" ++#include ++#include + +-int +-against_local_policy_as(register krb5_kdc_req *request, krb5_db_entry client, +- krb5_db_entry server, krb5_timestamp kdc_time, +- const char **status, krb5_pa_data ***e_data) ++typedef struct kdcpolicy_handle_st { ++ struct krb5_kdcpolicy_vtable_st vt; ++ krb5_kdcpolicy_moddata moddata; ++} *kdcpolicy_handle; ++ ++static kdcpolicy_handle *handles; ++ ++static void ++free_indicators(char **ais) + { +-#if 0 +- /* An AS request must include the addresses field */ +- if (request->addresses == 0) { +- *status = "NO ADDRESS"; +- return KRB5KDC_ERR_POLICY; +- } +-#endif ++ size_t i; + +- return 0; /* not against policy */ ++ if (ais == NULL) ++ return; ++ for (i = 0; ais[i] != NULL; i++) ++ free(ais[i]); ++ free(ais); ++} ++ ++/* Convert inds to a null-terminated list of C strings. */ ++static krb5_error_code ++authind_strings(krb5_data *const *inds, char ***strs_out) ++{ ++ krb5_error_code ret; ++ char **list = NULL; ++ size_t i, count; ++ ++ *strs_out = NULL; ++ ++ for (count = 0; inds != NULL && inds[count] != NULL; count++); ++ list = k5calloc(count + 1, sizeof(*list), &ret); ++ if (list == NULL) ++ goto error; ++ ++ for (i = 0; i < count; i++) { ++ list[i] = k5memdup0(inds[i]->data, inds[i]->length, &ret); ++ if (list[i] == NULL) ++ goto error; ++ } ++ ++ *strs_out = list; ++ return 0; ++ ++error: ++ free_indicators(list); ++ return ret; ++} ++ ++/* Constrain times->endtime to life and times->renew_till to rlife, relative to ++ * now. */ ++static void ++update_ticket_times(krb5_ticket_times *times, krb5_timestamp now, ++ krb5_deltat life, krb5_deltat rlife) ++{ ++ if (life) ++ times->endtime = ts_min(ts_incr(now, life), times->endtime); ++ if (rlife) ++ times->renew_till = ts_min(ts_incr(now, rlife), times->renew_till); ++} ++ ++/* Check an AS request against kdcpolicy modules, updating times with any ++ * module endtime constraints. Set an appropriate status string on error. */ ++krb5_error_code ++check_kdcpolicy_as(krb5_context context, const krb5_kdc_req *request, ++ const krb5_db_entry *client, const krb5_db_entry *server, ++ krb5_data *const *auth_indicators, krb5_timestamp kdc_time, ++ krb5_ticket_times *times, const char **status) ++{ ++ krb5_deltat life, rlife; ++ krb5_error_code ret; ++ kdcpolicy_handle *hp, h; ++ char **ais = NULL; ++ ++ *status = NULL; ++ ++ ret = authind_strings(auth_indicators, &ais); ++ if (ret) ++ goto done; ++ ++ for (hp = handles; *hp != NULL; hp++) { ++ h = *hp; ++ if (h->vt.check_as == NULL) ++ continue; ++ ++ ret = h->vt.check_as(context, h->moddata, request, client, server, ++ (const char **)ais, status, &life, &rlife); ++ if (ret) ++ goto done; ++ ++ update_ticket_times(times, kdc_time, life, rlife); ++ } ++ ++done: ++ free_indicators(ais); ++ return ret; + } + + /* +- * This is where local policy restrictions for the TGS should placed. ++ * Check the TGS request against the local TGS policy. Accepts an ++ * authentication indicator for the module policy decisions. Returns 0 and a ++ * NULL status string on success. + */ + krb5_error_code +-against_local_policy_tgs(register krb5_kdc_req *request, krb5_db_entry server, +- krb5_ticket *ticket, const char **status, +- krb5_pa_data ***e_data) ++check_kdcpolicy_tgs(krb5_context context, const krb5_kdc_req *request, ++ const krb5_db_entry *server, const krb5_ticket *ticket, ++ krb5_data *const *auth_indicators, krb5_timestamp kdc_time, ++ krb5_ticket_times *times, const char **status) + { +-#if 0 +- /* +- * For example, if your site wants to disallow ticket forwarding, +- * you might do something like this: +- */ ++ krb5_deltat life, rlife; ++ krb5_error_code ret; ++ kdcpolicy_handle *hp, h; ++ char **ais = NULL; + +- if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) { +- *status = "FORWARD POLICY"; +- return KRB5KDC_ERR_POLICY; ++ *status = NULL; ++ ++ ret = authind_strings(auth_indicators, &ais); ++ if (ret) ++ goto done; ++ ++ for (hp = handles; *hp != NULL; hp++) { ++ h = *hp; ++ if (h->vt.check_tgs == NULL) ++ continue; ++ ++ ret = h->vt.check_tgs(context, h->moddata, request, server, ticket, ++ (const char **)ais, status, &life, &rlife); ++ if (ret) ++ goto done; ++ ++ update_ticket_times(times, kdc_time, life, rlife); + } +-#endif + +- return 0; /* not against policy */ ++done: ++ free_indicators(ais); ++ return ret; ++} ++ ++void ++unload_kdcpolicy_plugins(krb5_context context) ++{ ++ kdcpolicy_handle *hp, h; ++ ++ for (hp = handles; *hp != NULL; hp++) { ++ h = *hp; ++ if (h->vt.fini != NULL) ++ h->vt.fini(context, h->moddata); ++ free(h); ++ } ++ free(handles); ++ handles = NULL; ++} ++ ++krb5_error_code ++load_kdcpolicy_plugins(krb5_context context) ++{ ++ krb5_error_code ret; ++ krb5_plugin_initvt_fn *modules = NULL, *mod; ++ kdcpolicy_handle h; ++ size_t count; ++ ++ ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_KDCPOLICY, &modules); ++ if (ret) ++ goto cleanup; ++ ++ for (count = 0; modules[count] != NULL; count++); ++ handles = k5calloc(count + 1, sizeof(*handles), &ret); ++ if (handles == NULL) ++ goto cleanup; ++ ++ count = 0; ++ for (mod = modules; *mod != NULL; mod++) { ++ h = k5calloc(1, sizeof(*h), &ret); ++ if (h == NULL) ++ goto cleanup; ++ ++ ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&h->vt); ++ if (ret) { /* Version mismatch. */ ++ TRACE_KDCPOLICY_VTINIT_FAIL(context, ret); ++ free(h); ++ continue; ++ } ++ if (h->vt.init != NULL) { ++ ret = h->vt.init(context, &h->moddata); ++ if (ret == KRB5_PLUGIN_NO_HANDLE) { ++ TRACE_KADM5_AUTH_INIT_SKIP(context, h->vt.name); ++ free(h); ++ continue; ++ } ++ if (ret) { ++ kdc_err(context, ret, _("while loading policy module %s"), ++ h->vt.name); ++ free(h); ++ goto cleanup; ++ } ++ } ++ handles[count++] = h; ++ } ++ ++ ret = 0; ++ ++cleanup: ++ if (ret) ++ unload_kdcpolicy_plugins(context); ++ k5_plugin_free_modules(context, modules); ++ return ret; + } +diff --git a/src/kdc/policy.h b/src/kdc/policy.h +index 6b000dc90..2a57b0a01 100644 +--- a/src/kdc/policy.h ++++ b/src/kdc/policy.h +@@ -26,11 +26,22 @@ + #ifndef __KRB5_KDC_POLICY__ + #define __KRB5_KDC_POLICY__ + +-extern int against_postdate_policy (krb5_timestamp); ++krb5_error_code ++load_kdcpolicy_plugins(krb5_context context); + +-extern int against_flag_policy_as (const krb5_kdc_req *); ++void ++unload_kdcpolicy_plugins(krb5_context context); + +-extern int against_flag_policy_tgs (const krb5_kdc_req *, +- const krb5_ticket *); ++krb5_error_code ++check_kdcpolicy_as(krb5_context context, const krb5_kdc_req *request, ++ const krb5_db_entry *client, const krb5_db_entry *server, ++ krb5_data *const *auth_indicators, krb5_timestamp kdc_time, ++ krb5_ticket_times *times, const char **status); ++ ++krb5_error_code ++check_kdcpolicy_tgs(krb5_context context, const krb5_kdc_req *request, ++ const krb5_db_entry *server, const krb5_ticket *ticket, ++ krb5_data *const *auth_indicators, krb5_timestamp kdc_time, ++ krb5_ticket_times *times, const char **status); + + #endif /* __KRB5_KDC_POLICY__ */ +diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c +index d0f25d1b7..33cfbcd81 100644 +--- a/src/kdc/tgs_policy.c ++++ b/src/kdc/tgs_policy.c +@@ -375,11 +375,5 @@ validate_tgs_request(kdc_realm_t *kdc_active_realm, + if (ret && ret != KRB5_PLUGIN_OP_NOTSUPP) + return errcode_to_protocol(ret); + +- /* Check local policy. */ +- errcode = against_local_policy_tgs(request, server, ticket, +- status, e_data); +- if (errcode) +- return errcode; +- + return 0; + } +diff --git a/src/lib/krb5/krb/plugin.c b/src/lib/krb5/krb/plugin.c +index 17dd6bd30..31aaf661d 100644 +--- a/src/lib/krb5/krb/plugin.c ++++ b/src/lib/krb5/krb/plugin.c +@@ -58,7 +58,9 @@ const char *interface_names[] = { + "audit", + "tls", + "kdcauthdata", +- "certauth" ++ "certauth", ++ "kadm5_auth", ++ "kdcpolicy", + }; + + /* Return the context's interface structure for id, or NULL if invalid. */ +diff --git a/src/plugins/kdcpolicy/test/Makefile.in b/src/plugins/kdcpolicy/test/Makefile.in +new file mode 100644 +index 000000000..b81f1a7ce +--- /dev/null ++++ b/src/plugins/kdcpolicy/test/Makefile.in +@@ -0,0 +1,20 @@ ++mydir=plugins$(S)policy$(S)test ++BUILDTOP=$(REL)..$(S)..$(S).. ++ ++LIBBASE=policy_test ++LIBMAJOR=0 ++LIBMINOR=0 ++RELDIR=../plugins/kdcpolicy/test ++SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS) ++SHLIB_EXPLIBS=$(KRB5_BASE_LIBS) ++ ++STLIBOBJS=main.o ++ ++SRCS=$(srcdir)/main.c ++ ++all-unix: all-libs ++install-unix: ++clean-unix:: clean-libs clean-libobjs ++ ++@libnover_frag@ ++@libobj_frag@ +diff --git a/src/plugins/kdcpolicy/test/deps b/src/plugins/kdcpolicy/test/deps +new file mode 100644 +index 000000000..e69de29bb +diff --git a/src/plugins/kdcpolicy/test/main.c b/src/plugins/kdcpolicy/test/main.c +new file mode 100644 +index 000000000..eb8fde053 +--- /dev/null ++++ b/src/plugins/kdcpolicy/test/main.c +@@ -0,0 +1,111 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* include/krb5/kdcpolicy_plugin.h - KDC policy plugin interface */ ++/* ++ * Copyright (C) 2017 by Red Hat, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "k5-int.h" ++#include "kdb.h" ++#include ++ ++static krb5_error_code ++output_from_indicator(const char *const *auth_indicators, ++ krb5_deltat *lifetime_out, ++ krb5_deltat *renew_lifetime_out, ++ const char **status) ++{ ++ if (auth_indicators[0] == NULL) { ++ *status = NULL; ++ return 0; ++ } ++ ++ if (strcmp(auth_indicators[0], "ONE_HOUR") == 0) { ++ *lifetime_out = 3600; ++ *renew_lifetime_out = *lifetime_out * 2; ++ return 0; ++ } else if (strcmp(auth_indicators[0], "SEVEN_HOURS") == 0) { ++ *lifetime_out = 7 * 3600; ++ *renew_lifetime_out = *lifetime_out * 2; ++ return 0; ++ } ++ ++ *status = "LOCAL_POLICY"; ++ return KRB5KDC_ERR_POLICY; ++} ++ ++static krb5_error_code ++test_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata, ++ const krb5_kdc_req *request, const krb5_db_entry *client, ++ const krb5_db_entry *server, const char *const *auth_indicators, ++ const char **status, krb5_deltat *lifetime_out, ++ krb5_deltat *renew_lifetime_out) ++{ ++ if (request->client != NULL && request->client->length >= 1 && ++ data_eq_string(request->client->data[0], "fail")) { ++ *status = "LOCAL_POLICY"; ++ return KRB5KDC_ERR_POLICY; ++ } ++ return output_from_indicator(auth_indicators, lifetime_out, ++ renew_lifetime_out, status); ++} ++ ++static krb5_error_code ++test_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata, ++ const krb5_kdc_req *request, const krb5_db_entry *server, ++ const krb5_ticket *ticket, const char *const *auth_indicators, ++ const char **status, krb5_deltat *lifetime_out, ++ krb5_deltat *renew_lifetime_out) ++{ ++ if (request->server != NULL && request->server->length >= 1 && ++ data_eq_string(request->server->data[0], "fail")) { ++ *status = "LOCAL_POLICY"; ++ return KRB5KDC_ERR_POLICY; ++ } ++ return output_from_indicator(auth_indicators, lifetime_out, ++ renew_lifetime_out, status); ++} ++ ++krb5_error_code ++kdcpolicy_test_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable); ++krb5_error_code ++kdcpolicy_test_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable) ++{ ++ krb5_kdcpolicy_vtable vt; ++ ++ if (maj_ver != 1) ++ return KRB5_PLUGIN_VER_NOTSUPP; ++ ++ vt = (krb5_kdcpolicy_vtable)vtable; ++ vt->name = "test"; ++ vt->check_as = test_check_as; ++ vt->check_tgs = test_check_tgs; ++ return 0; ++} +diff --git a/src/plugins/kdcpolicy/test/policy_test.exports b/src/plugins/kdcpolicy/test/policy_test.exports +new file mode 100644 +index 000000000..9682ec74f +--- /dev/null ++++ b/src/plugins/kdcpolicy/test/policy_test.exports +@@ -0,0 +1 @@ ++kdcpolicy_test_initvt +diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in +index 2b3112537..a2093108b 100644 +--- a/src/tests/Makefile.in ++++ b/src/tests/Makefile.in +@@ -169,6 +169,7 @@ check-pytests: localauth plugorder rdreq responder s2p s4u2proxy unlockiter + $(RUNPYTEST) $(srcdir)/t_tabdump.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_certauth.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_y2038.py $(PYTESTFLAGS) ++ $(RUNPYTEST) $(srcdir)/t_kdcpolicy.py $(PYTESTFLAGS) + + clean: + $(RM) adata etinfo forward gcred hist hooks hrealm icred kdbtest +diff --git a/src/tests/t_kdcpolicy.py b/src/tests/t_kdcpolicy.py +new file mode 100644 +index 000000000..6a745b959 +--- /dev/null ++++ b/src/tests/t_kdcpolicy.py +@@ -0,0 +1,57 @@ ++#!/usr/bin/python ++from k5test import * ++from datetime import datetime ++import re ++ ++testpreauth = os.path.join(buildtop, 'plugins', 'preauth', 'test', 'test.so') ++testpolicy = os.path.join(buildtop, 'plugins', 'kdcpolicy', 'test', ++ 'policy_test.so') ++krb5_conf = {'plugins': {'kdcpreauth': {'module': 'test:' + testpreauth}, ++ 'clpreauth': {'module': 'test:' + testpreauth}, ++ 'kdcpolicy': {'module': 'test:' + testpolicy}}} ++kdc_conf = {'realms': {'$realm': {'default_principal_flags': '+preauth', ++ 'max_renewable_life': '1d'}}} ++realm = K5Realm(krb5_conf=krb5_conf, kdc_conf=kdc_conf) ++ ++realm.run([kadminl, 'addprinc', '-pw', password('fail'), 'fail']) ++ ++def verify_time(out, target_time): ++ times = re.findall(r'\d\d/\d\d/\d\d \d\d:\d\d:\d\d', out) ++ times = [datetime.strptime(t, '%m/%d/%y %H:%M:%S') for t in times] ++ while len(times) > 0: ++ starttime = times.pop(0) ++ endtime = times.pop(0) ++ renewtime = times.pop(0) ++ ++ if str(endtime - starttime) != target_time: ++ fail('unexpected lifetime value') ++ if str(renewtime - endtime) != target_time: ++ fail('unexpected renewable value') ++ ++rflags = ['-r', '1d', '-l', '12h'] ++ ++# Test AS+TGS success path. ++realm.kinit(realm.user_princ, password('user'), ++ rflags + ['-X', 'indicators=SEVEN_HOURS']) ++realm.run([kvno, realm.host_princ]) ++realm.run(['./adata', realm.host_princ], expected_msg='+97: [SEVEN_HOURS]') ++out = realm.run([klist, realm.ccache, '-e']) ++verify_time(out, '7:00:00') ++ ++# Test AS+TGS success path with different values. ++realm.kinit(realm.user_princ, password('user'), ++ rflags + ['-X', 'indicators=ONE_HOUR']) ++realm.run([kvno, realm.host_princ]) ++realm.run(['./adata', realm.host_princ], expected_msg='+97: [ONE_HOUR]') ++out = realm.run([klist, realm.ccache, '-e']) ++verify_time(out, '1:00:00') ++ ++# Test TGS failure path (using previous creds). ++realm.run([kvno, 'fail@%s' % realm.realm], expected_code=1, ++ expected_msg='KDC policy rejects request') ++ ++# Test AS failure path. ++realm.kinit('fail@%s' % realm.realm, password('fail'), ++ expected_code=1, expected_msg='KDC policy rejects request') ++ ++success('kdcpolicy tests') diff --git a/SOURCES/Add-PKINIT-UPN-tests-to-t_pkinit.py.patch b/SOURCES/Add-PKINIT-UPN-tests-to-t_pkinit.py.patch new file mode 100644 index 0000000..5d43ea7 --- /dev/null +++ b/SOURCES/Add-PKINIT-UPN-tests-to-t_pkinit.py.patch @@ -0,0 +1,102 @@ +From f726fe232a16a51ca277b660c61aa9cfc2f512f1 Mon Sep 17 00:00:00 2001 +From: Matt Rogers +Date: Fri, 9 Dec 2016 11:43:27 -0500 +Subject: [PATCH] Add PKINIT UPN tests to t_pkinit.py + +[ghudson@mit.edu: simplify and explain tests; add test for +id-pkinit-san match against canonicalized client principal] + +ticket: 8528 +(cherry picked from commit d520fd3f032121b61b22681838af96ee505fe44d) +Signed-off-by: Robbie Harwood +--- + src/tests/t_pkinit.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py +index 526473b42..ac4d326b6 100755 +--- a/src/tests/t_pkinit.py ++++ b/src/tests/t_pkinit.py +@@ -23,6 +23,9 @@ privkey_pem = os.path.join(certs, 'privkey.pem') + privkey_enc_pem = os.path.join(certs, 'privkey-enc.pem') + user_p12 = os.path.join(certs, 'user.p12') + user_enc_p12 = os.path.join(certs, 'user-enc.p12') ++user_upn_p12 = os.path.join(certs, 'user-upn.p12') ++user_upn2_p12 = os.path.join(certs, 'user-upn2.p12') ++user_upn3_p12 = os.path.join(certs, 'user-upn3.p12') + path = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs') + path_enc = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs-enc') + +@@ -36,6 +39,20 @@ pkinit_kdc_conf = {'realms': {'$realm': { + restrictive_kdc_conf = {'realms': {'$realm': { + 'restrict_anonymous_to_tgt': 'true' }}} + ++testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'}, ++ 'user': {'keys': 'aes128-cts', 'flags': '+preauth'}, ++ 'user2': {'keys': 'aes128-cts', 'flags': '+preauth'}} ++alias_kdc_conf = {'realms': {'$realm': { ++ 'default_principal_flags': '+preauth', ++ 'pkinit_eku_checking': 'none', ++ 'pkinit_allow_upn': 'true', ++ 'pkinit_identity': 'FILE:%s,%s' % (kdc_pem, privkey_pem), ++ 'database_module': 'test'}}, ++ 'dbmodules': {'test': { ++ 'db_library': 'test', ++ 'alias': {'user@krbtest.com': 'user'}, ++ 'princs': testprincs}}} ++ + file_identity = 'FILE:%s,%s' % (user_pem, privkey_pem) + file_enc_identity = 'FILE:%s,%s' % (user_pem, privkey_enc_pem) + dir_identity = 'DIR:%s' % path +@@ -45,11 +62,51 @@ dir_file_identity = 'FILE:%s,%s' % (os.path.join(path, 'user.crt'), + dir_file_enc_identity = 'FILE:%s,%s' % (os.path.join(path_enc, 'user.crt'), + os.path.join(path_enc, 'user.key')) + p12_identity = 'PKCS12:%s' % user_p12 ++p12_upn_identity = 'PKCS12:%s' % user_upn_p12 ++p12_upn2_identity = 'PKCS12:%s' % user_upn2_p12 ++p12_upn3_identity = 'PKCS12:%s' % user_upn3_p12 + p12_enc_identity = 'PKCS12:%s' % user_enc_p12 + p11_identity = 'PKCS11:soft-pkcs11.so' + p11_token_identity = ('PKCS11:module_name=soft-pkcs11.so:' + 'slotid=1:token=SoftToken (token)') + ++# Start a realm with the test kdb module for the following UPN SAN tests. ++realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=alias_kdc_conf, ++ create_kdb=False) ++realm.start_kdc() ++ ++# Compatibility check: cert contains UPN "user", which matches the ++# request principal user@KRBTEST.COM if parsed as a normal principal. ++realm.kinit(realm.user_princ, ++ flags=['-X', 'X509_user_identity=%s' % p12_upn2_identity]) ++ ++# Compatibility check: cert contains UPN "user@KRBTEST.COM", which matches ++# the request principal user@KRBTEST.COM if parsed as a normal principal. ++realm.kinit(realm.user_princ, ++ flags=['-X', 'X509_user_identity=%s' % p12_upn3_identity]) ++ ++# Cert contains UPN "user@krbtest.com" which is aliased to the request ++# principal. ++realm.kinit(realm.user_princ, ++ flags=['-X', 'X509_user_identity=%s' % p12_upn_identity]) ++ ++# Test an id-pkinit-san match to a post-canonical principal. ++realm.kinit('user@krbtest.com', ++ flags=['-E', '-X', 'X509_user_identity=%s' % p12_identity]) ++ ++# Test a UPN match to a post-canonical principal. (This only works ++# for the cert with the UPN containing just "user", as we don't allow ++# UPN reparsing when comparing to the canonicalized client principal.) ++realm.kinit('user@krbtest.com', ++ flags=['-E', '-X', 'X509_user_identity=%s' % p12_upn2_identity]) ++ ++# Test a mismatch. ++out = realm.run([kinit, '-X', 'X509_user_identity=%s' % p12_upn2_identity, ++ 'user2'], expected_code=1) ++if 'kinit: Client name mismatch while getting initial credentials' not in out: ++ fail('Wrong error for UPN SAN mismatch') ++realm.stop() ++ + realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=pkinit_kdc_conf, + get_creds=False) + diff --git a/SOURCES/Add-certauth-pluggable-interface.patch b/SOURCES/Add-certauth-pluggable-interface.patch index 30a25ca..79bd718 100644 --- a/SOURCES/Add-certauth-pluggable-interface.patch +++ b/SOURCES/Add-certauth-pluggable-interface.patch @@ -1,4 +1,4 @@ -From c206d6f3351d51ef3a916ef8522ab58c1a8572f7 Mon Sep 17 00:00:00 2001 +From 5a0b9b43a070c273ae4ee39ee460fa759ff9d934 Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Tue, 28 Feb 2017 15:55:24 -0500 Subject: [PATCH] Add certauth pluggable interface @@ -22,6 +22,7 @@ doc/plugindev/certauth.rst and doc/admin/krb5_conf.rst. ticket: 8561 (new) (cherry picked from commit b619ce84470519bea65470be3263cd85fba94f57) +Signed-off-by: Robbie Harwood --- doc/admin/conf_files/krb5_conf.rst | 21 ++ doc/plugindev/certauth.rst | 27 ++ diff --git a/SOURCES/Add-k5test-expected_msg-expected_trace.patch b/SOURCES/Add-k5test-expected_msg-expected_trace.patch new file mode 100644 index 0000000..c07c519 --- /dev/null +++ b/SOURCES/Add-k5test-expected_msg-expected_trace.patch @@ -0,0 +1,97 @@ +From c099e896f28d8c5ccacc9df086a8f4297c6b484e Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Tue, 17 Jan 2017 11:24:41 -0500 +Subject: [PATCH] Add k5test expected_msg, expected_trace + +In k5test.py, add the optional keyword argument "expected_msg" to +methods that run commands, to make it easier to look for substrings in +the command output. Add the optional keyword "expected_trace" to run +the command with KRB5_TRACE enabled and look for an ordered series of +substrings in the trace output. + +(cherry picked from commit 8bb5fce69a4aa6c3082fa7def66a93974e10e17a) +[rharwood@redhat.com: back out .gitignore] +Signed-off-by: Robbie Harwood +--- + src/config/post.in | 2 +- + src/util/k5test.py | 37 ++++++++++++++++++++++++++++++++++--- + 2 files changed, 35 insertions(+), 4 deletions(-) + +diff --git a/src/config/post.in b/src/config/post.in +index 77a9bffdf..aecac9d3b 100644 +--- a/src/config/post.in ++++ b/src/config/post.in +@@ -156,7 +156,7 @@ clean: clean-$(WHAT) + + clean-unix:: + $(RM) $(OBJS) $(DEPTARGETS_CLEAN) $(EXTRA_FILES) +- $(RM) et-[ch]-*.et et-[ch]-*.[ch] testlog ++ $(RM) et-[ch]-*.et et-[ch]-*.[ch] testlog testtrace + -$(RM) -r testdir + + clean-windows:: +diff --git a/src/util/k5test.py b/src/util/k5test.py +index c3d026377..4d30baf40 100644 +--- a/src/util/k5test.py ++++ b/src/util/k5test.py +@@ -223,8 +223,11 @@ Scripts may use the following realm methods and attributes: + command-line debugging options. Fail if the command does not return + 0. Log the command output appropriately, and return it as a single + multi-line string. Keyword arguments can contain input='string' to +- send an input string to the command, and expected_code=N to expect a +- return code other than 0. ++ send an input string to the command, expected_code=N to expect a ++ return code other than 0, expected_msg=MSG to expect a substring in ++ the command output, and expected_trace=('a', 'b', ...) to expect an ++ ordered series of line substrings in the command's KRB5_TRACE ++ output. + + * realm.kprop_port(): Returns a port number based on realm.portbase + intended for use by kprop and kpropd. +@@ -647,10 +650,31 @@ def _stop_or_shell(stop, shell, env, ind): + subprocess.call(os.getenv('SHELL'), env=env) + + +-def _run_cmd(args, env, input=None, expected_code=0): ++# Read tracefile and look for the expected strings in successive lines. ++def _check_trace(tracefile, expected): ++ output('*** Trace output for previous command:\n') ++ i = 0 ++ with open(tracefile, 'r') as f: ++ for line in f: ++ output(line) ++ if i < len(expected) and expected[i] in line: ++ i += 1 ++ if i < len(expected): ++ fail('Expected string not found in trace output: ' + expected[i]) ++ ++ ++def _run_cmd(args, env, input=None, expected_code=0, expected_msg=None, ++ expected_trace=None): + global null_input, _cmd_index, _last_cmd, _last_cmd_output, _debug + global _stop_before, _stop_after, _shell_before, _shell_after + ++ if expected_trace is not None: ++ tracefile = 'testtrace' ++ if os.path.exists(tracefile): ++ os.remove(tracefile) ++ env = env.copy() ++ env['KRB5_TRACE'] = tracefile ++ + if (_match_cmdnum(_debug, _cmd_index)): + return _debug_cmd(args, env, input) + +@@ -679,6 +703,13 @@ def _run_cmd(args, env, input=None, expected_code=0): + # Check the return code and return the output. + if code != expected_code: + fail('%s failed with code %d.' % (args[0], code)) ++ ++ if expected_msg is not None and expected_msg not in outdata: ++ fail('Expected string not found in command output: ' + expected_msg) ++ ++ if expected_trace is not None: ++ _check_trace(tracefile, expected_trace) ++ + return outdata + + diff --git a/SOURCES/Add-support-to-query-the-SSF-of-a-GSS-context.patch b/SOURCES/Add-support-to-query-the-SSF-of-a-GSS-context.patch new file mode 100644 index 0000000..cc0ddb3 --- /dev/null +++ b/SOURCES/Add-support-to-query-the-SSF-of-a-GSS-context.patch @@ -0,0 +1,420 @@ +From 1f7d42707585e552842455857070fff8957fcb7c Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Thu, 30 Mar 2017 11:27:09 -0400 +Subject: [PATCH] Add support to query the SSF of a GSS context + +Cyrus SASL provides a Security Strength Factor number to assess the +relative "strength" of the negotiated mechanism, and applications +sometimes make access control decisions based on it. + +Add a call that allows us to query the mechanism that established the +GSS security context to ask what is the current SSF, based on the +enctype of the session key. + +ticket: 8569 (new) +(cherry picked from commit 7feb7da54c0321b5a3eeb6c3797846a3cf7eda28) +[rharwood@redhat.com: stub out GSS_KRB5_GET_CRED_IMPERSONATOR] +Signed-off-by: Robbie Harwood +--- + src/include/k5-int.h | 1 + + src/lib/crypto/krb/crypto_int.h | 1 + + src/lib/crypto/krb/enctype_util.c | 16 ++++++++++++++++ + src/lib/crypto/krb/etypes.c | 33 ++++++++++++++++++--------------- + src/lib/crypto/libk5crypto.exports | 1 + + src/lib/gssapi/generic/gssapi_ext.h | 11 +++++++++++ + src/lib/gssapi/generic/gssapi_generic.c | 9 +++++++++ + src/lib/gssapi/krb5/gssapiP_krb5.h | 6 ++++++ + src/lib/gssapi/krb5/gssapi_krb5.c | 4 ++++ + src/lib/gssapi/krb5/inq_context.c | 27 +++++++++++++++++++++++++++ + src/lib/gssapi/libgssapi_krb5.exports | 1 + + src/lib/gssapi32.def | 3 +++ + src/lib/krb5_32.def | 3 +++ + src/tests/gssapi/t_enctypes.c | 14 ++++++++++++++ + 14 files changed, 115 insertions(+), 15 deletions(-) + +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index cea644d0a..06ca2b66d 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -2114,6 +2114,7 @@ krb5_get_tgs_ktypes(krb5_context, krb5_const_principal, krb5_enctype **); + krb5_boolean krb5_is_permitted_enctype(krb5_context, krb5_enctype); + + krb5_boolean KRB5_CALLCONV krb5int_c_weak_enctype(krb5_enctype); ++krb5_error_code k5_enctype_to_ssf(krb5_enctype enctype, unsigned int *ssf_out); + + krb5_error_code krb5_kdc_rep_decrypt_proc(krb5_context, const krb5_keyblock *, + krb5_const_pointer, krb5_kdc_rep *); +diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h +index d75b49c69..e5099291e 100644 +--- a/src/lib/crypto/krb/crypto_int.h ++++ b/src/lib/crypto/krb/crypto_int.h +@@ -111,6 +111,7 @@ struct krb5_keytypes { + prf_func prf; + krb5_cksumtype required_ctype; + krb5_flags flags; ++ unsigned int ssf; + }; + + #define ETYPE_WEAK 1 +diff --git a/src/lib/crypto/krb/enctype_util.c b/src/lib/crypto/krb/enctype_util.c +index 0ed74bd6e..b1b40e7ec 100644 +--- a/src/lib/crypto/krb/enctype_util.c ++++ b/src/lib/crypto/krb/enctype_util.c +@@ -131,3 +131,19 @@ krb5_enctype_to_name(krb5_enctype enctype, krb5_boolean shortest, + return ENOMEM; + return 0; + } ++ ++/* The security of a mechanism cannot be summarized with a simple integer ++ * value, but we provide a per-enctype value for Cyrus SASL's SSF. */ ++krb5_error_code ++k5_enctype_to_ssf(krb5_enctype enctype, unsigned int *ssf_out) ++{ ++ const struct krb5_keytypes *ktp; ++ ++ *ssf_out = 0; ++ ++ ktp = find_enctype(enctype); ++ if (ktp == NULL) ++ return EINVAL; ++ *ssf_out = ktp->ssf; ++ return 0; ++} +diff --git a/src/lib/crypto/krb/etypes.c b/src/lib/crypto/krb/etypes.c +index 0e5e977d4..53d4a5c79 100644 +--- a/src/lib/crypto/krb/etypes.c ++++ b/src/lib/crypto/krb/etypes.c +@@ -42,7 +42,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_des_string_to_key, k5_rand2key_des, + krb5int_des_prf, + CKSUMTYPE_RSA_MD5_DES, +- ETYPE_WEAK }, ++ ETYPE_WEAK, 56 }, + { ENCTYPE_DES_CBC_MD4, + "des-cbc-md4", { 0 }, "DES cbc mode with RSA-MD4", + &krb5int_enc_des, &krb5int_hash_md4, +@@ -51,7 +51,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_des_string_to_key, k5_rand2key_des, + krb5int_des_prf, + CKSUMTYPE_RSA_MD4_DES, +- ETYPE_WEAK }, ++ ETYPE_WEAK, 56 }, + { ENCTYPE_DES_CBC_MD5, + "des-cbc-md5", { "des" }, "DES cbc mode with RSA-MD5", + &krb5int_enc_des, &krb5int_hash_md5, +@@ -60,7 +60,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_des_string_to_key, k5_rand2key_des, + krb5int_des_prf, + CKSUMTYPE_RSA_MD5_DES, +- ETYPE_WEAK }, ++ ETYPE_WEAK, 56 }, + { ENCTYPE_DES_CBC_RAW, + "des-cbc-raw", { 0 }, "DES cbc mode raw", + &krb5int_enc_des, NULL, +@@ -69,7 +69,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_des_string_to_key, k5_rand2key_des, + krb5int_des_prf, + 0, +- ETYPE_WEAK }, ++ ETYPE_WEAK, 56 }, + { ENCTYPE_DES3_CBC_RAW, + "des3-cbc-raw", { 0 }, "Triple DES cbc mode raw", + &krb5int_enc_des3, NULL, +@@ -78,7 +78,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_dk_string_to_key, k5_rand2key_des3, + NULL, /*PRF*/ + 0, +- ETYPE_WEAK }, ++ ETYPE_WEAK, 112 }, + + { ENCTYPE_DES3_CBC_SHA1, + "des3-cbc-sha1", { "des3-hmac-sha1", "des3-cbc-sha1-kd" }, +@@ -89,7 +89,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_dk_string_to_key, k5_rand2key_des3, + krb5int_dk_prf, + CKSUMTYPE_HMAC_SHA1_DES3, +- 0 /*flags*/ }, ++ 0 /*flags*/, 112 }, + + { ENCTYPE_DES_HMAC_SHA1, + "des-hmac-sha1", { 0 }, "DES with HMAC/sha1", +@@ -99,7 +99,10 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_dk_string_to_key, k5_rand2key_des, + NULL, /*PRF*/ + 0, +- ETYPE_WEAK }, ++ ETYPE_WEAK, 56 }, ++ ++ /* rc4-hmac uses a 128-bit key, but due to weaknesses in the RC4 cipher, we ++ * consider its strength degraded and assign it an SSF value of 64. */ + { ENCTYPE_ARCFOUR_HMAC, + "arcfour-hmac", { "rc4-hmac", "arcfour-hmac-md5" }, + "ArcFour with HMAC/md5", +@@ -110,7 +113,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key, + k5_rand2key_direct, krb5int_arcfour_prf, + CKSUMTYPE_HMAC_MD5_ARCFOUR, +- 0 /*flags*/ }, ++ 0 /*flags*/, 64 }, + { ENCTYPE_ARCFOUR_HMAC_EXP, + "arcfour-hmac-exp", { "rc4-hmac-exp", "arcfour-hmac-md5-exp" }, + "Exportable ArcFour with HMAC/md5", +@@ -121,7 +124,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key, + k5_rand2key_direct, krb5int_arcfour_prf, + CKSUMTYPE_HMAC_MD5_ARCFOUR, +- ETYPE_WEAK ++ ETYPE_WEAK, 40 + }, + + { ENCTYPE_AES128_CTS_HMAC_SHA1_96, +@@ -133,7 +136,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_aes_string_to_key, k5_rand2key_direct, + krb5int_dk_prf, + CKSUMTYPE_HMAC_SHA1_96_AES128, +- 0 /*flags*/ }, ++ 0 /*flags*/, 128 }, + { ENCTYPE_AES256_CTS_HMAC_SHA1_96, + "aes256-cts-hmac-sha1-96", { "aes256-cts", "aes256-sha1" }, + "AES-256 CTS mode with 96-bit SHA-1 HMAC", +@@ -143,7 +146,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_aes_string_to_key, k5_rand2key_direct, + krb5int_dk_prf, + CKSUMTYPE_HMAC_SHA1_96_AES256, +- 0 /*flags*/ }, ++ 0 /*flags*/, 256 }, + + { ENCTYPE_CAMELLIA128_CTS_CMAC, + "camellia128-cts-cmac", { "camellia128-cts" }, +@@ -155,7 +158,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_camellia_string_to_key, k5_rand2key_direct, + krb5int_dk_cmac_prf, + CKSUMTYPE_CMAC_CAMELLIA128, +- 0 /*flags*/ }, ++ 0 /*flags*/, 128 }, + { ENCTYPE_CAMELLIA256_CTS_CMAC, + "camellia256-cts-cmac", { "camellia256-cts" }, + "Camellia-256 CTS mode with CMAC", +@@ -166,7 +169,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_camellia_string_to_key, k5_rand2key_direct, + krb5int_dk_cmac_prf, + CKSUMTYPE_CMAC_CAMELLIA256, +- 0 /*flags */ }, ++ 0 /*flags */, 256 }, + + { ENCTYPE_AES128_CTS_HMAC_SHA256_128, + "aes128-cts-hmac-sha256-128", { "aes128-sha2" }, +@@ -177,7 +180,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_aes2_string_to_key, k5_rand2key_direct, + krb5int_aes2_prf, + CKSUMTYPE_HMAC_SHA256_128_AES128, +- 0 /*flags*/ }, ++ 0 /*flags*/, 128 }, + { ENCTYPE_AES256_CTS_HMAC_SHA384_192, + "aes256-cts-hmac-sha384-192", { "aes256-sha2" }, + "AES-256 CTS mode with 192-bit SHA-384 HMAC", +@@ -187,7 +190,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { + krb5int_aes2_string_to_key, k5_rand2key_direct, + krb5int_aes2_prf, + CKSUMTYPE_HMAC_SHA384_192_AES256, +- 0 /*flags*/ }, ++ 0 /*flags*/, 256 }, + }; + + const int krb5int_enctypes_length = +diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports +index 447e45644..82eb5f30c 100644 +--- a/src/lib/crypto/libk5crypto.exports ++++ b/src/lib/crypto/libk5crypto.exports +@@ -108,3 +108,4 @@ krb5int_nfold + k5_allow_weak_pbkdf2iter + krb5_c_prfplus + krb5_c_derive_prfplus ++k5_enctype_to_ssf +diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h +index 9ad44216d..9d3a7e736 100644 +--- a/src/lib/gssapi/generic/gssapi_ext.h ++++ b/src/lib/gssapi/generic/gssapi_ext.h +@@ -575,4 +575,15 @@ gss_import_cred( + } + #endif + ++/* ++ * When used with gss_inquire_sec_context_by_oid(), return a buffer set with ++ * the first member containing an unsigned 32-bit integer in network byte ++ * order. This is the Security Strength Factor (SSF) associated with the ++ * secure channel established by the security context. NOTE: This value is ++ * made available solely as an indication for use by APIs like Cyrus SASL that ++ * classify the strength of a secure channel via this number. The strength of ++ * a channel cannot necessarily be represented by a simple number. ++ */ ++GSS_DLLIMP extern gss_OID GSS_C_SEC_CONTEXT_SASL_SSF; ++ + #endif /* GSSAPI_EXT_H_ */ +diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c +index 5496aa335..fa144c2bf 100644 +--- a/src/lib/gssapi/generic/gssapi_generic.c ++++ b/src/lib/gssapi/generic/gssapi_generic.c +@@ -157,6 +157,13 @@ static const gss_OID_desc const_oids[] = { + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x19"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1a"}, + {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1b"}, ++ ++ /* ++ * GSS_SEC_CONTEXT_SASL_SSF_OID 1.2.840.113554.1.2.2.5.15 ++ * iso(1) member-body(2) United States(840) mit(113554) ++ * infosys(1) gssapi(2) krb5(2) krb5-gssapi-ext(5) sasl-ssf(15) ++ */ ++ {11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"}, + }; + + /* Here are the constants which point to the static structure above. +@@ -218,6 +225,8 @@ GSS_DLLIMP gss_const_OID GSS_C_MA_PFS = oids+33; + GSS_DLLIMP gss_const_OID GSS_C_MA_COMPRESS = oids+34; + GSS_DLLIMP gss_const_OID GSS_C_MA_CTX_TRANS = oids+35; + ++GSS_DLLIMP gss_OID GSS_C_SEC_CONTEXT_SASL_SSF = oids+36; ++ + static gss_OID_set_desc gss_ma_known_attrs_desc = { 27, oids+9 }; + gss_OID_set gss_ma_known_attrs = &gss_ma_known_attrs_desc; + +diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h +index d7bdef7e2..ef030707e 100644 +--- a/src/lib/gssapi/krb5/gssapiP_krb5.h ++++ b/src/lib/gssapi/krb5/gssapiP_krb5.h +@@ -1144,6 +1144,12 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *, + const gss_OID, + gss_buffer_set_t *); + ++#define GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH 11 ++#define GET_SEC_CONTEXT_SASL_SSF_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f" ++OM_uint32 ++gss_krb5int_sec_context_sasl_ssf(OM_uint32 *, const gss_ctx_id_t, ++ const gss_OID, gss_buffer_set_t *); ++ + #define GSS_KRB5_IMPORT_CRED_OID_LENGTH 11 + #define GSS_KRB5_IMPORT_CRED_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0d" + +diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c +index 99092ccab..de4131980 100644 +--- a/src/lib/gssapi/krb5/gssapi_krb5.c ++++ b/src/lib/gssapi/krb5/gssapi_krb5.c +@@ -352,6 +352,10 @@ static struct { + { + {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID}, + gss_krb5int_extract_authtime_from_sec_context ++ }, ++ { ++ {GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH, GET_SEC_CONTEXT_SASL_SSF_OID}, ++ gss_krb5int_sec_context_sasl_ssf + } + }; + +diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c +index 9024b3c7e..d2e466e60 100644 +--- a/src/lib/gssapi/krb5/inq_context.c ++++ b/src/lib/gssapi/krb5/inq_context.c +@@ -310,3 +310,30 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status, + + return generic_gss_add_buffer_set_member(minor_status, &rep, data_set); + } ++ ++OM_uint32 ++gss_krb5int_sec_context_sasl_ssf(OM_uint32 *minor_status, ++ const gss_ctx_id_t context_handle, ++ const gss_OID desired_object, ++ gss_buffer_set_t *data_set) ++{ ++ krb5_gss_ctx_id_rec *ctx; ++ krb5_key key; ++ krb5_error_code code; ++ gss_buffer_desc ssfbuf; ++ unsigned int ssf; ++ uint8_t buf[4]; ++ ++ ctx = (krb5_gss_ctx_id_rec *)context_handle; ++ key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey; ++ ++ code = k5_enctype_to_ssf(key->keyblock.enctype, &ssf); ++ if (code) ++ return GSS_S_FAILURE; ++ ++ store_32_be(ssf, buf); ++ ssfbuf.value = buf; ++ ssfbuf.length = sizeof(buf); ++ ++ return generic_gss_add_buffer_set_member(minor_status, &ssfbuf, data_set); ++} +diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports +index 9facb3f42..936540e41 100644 +--- a/src/lib/gssapi/libgssapi_krb5.exports ++++ b/src/lib/gssapi/libgssapi_krb5.exports +@@ -37,6 +37,7 @@ GSS_C_MA_CBINDINGS + GSS_C_MA_PFS + GSS_C_MA_COMPRESS + GSS_C_MA_CTX_TRANS ++GSS_C_SEC_CONTEXT_SASL_SSF + gss_accept_sec_context + gss_acquire_cred + gss_acquire_cred_with_password +diff --git a/src/lib/gssapi32.def b/src/lib/gssapi32.def +index 362b9bce8..dff057754 100644 +--- a/src/lib/gssapi32.def ++++ b/src/lib/gssapi32.def +@@ -182,3 +182,6 @@ EXPORTS + gss_verify_mic_iov @146 + ; Added in 1.14 + GSS_KRB5_CRED_NO_CI_FLAGS_X @147 DATA ++; Added in 1.16 ++; GSS_KRB5_GET_CRED_IMPERSONATOR @148 DATA ++ GSS_C_SEC_CONTEXT_SASL_SSF @149 DATA +diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def +index e5b560dfc..f7b428e16 100644 +--- a/src/lib/krb5_32.def ++++ b/src/lib/krb5_32.def +@@ -470,3 +470,6 @@ EXPORTS + krb5_get_init_creds_opt_set_pac_request @435 + krb5int_trace @436 ; PRIVATE GSSAPI + krb5_expand_hostname @437 ++ ++; new in 1.16 ++ k5_enctype_to_ssf @438 ; PRIVATE GSSAPI +diff --git a/src/tests/gssapi/t_enctypes.c b/src/tests/gssapi/t_enctypes.c +index a2ad18f47..3fd31e2f8 100644 +--- a/src/tests/gssapi/t_enctypes.c ++++ b/src/tests/gssapi/t_enctypes.c +@@ -32,6 +32,7 @@ + + #include "k5-int.h" + #include "common.h" ++#include "gssapi_ext.h" + + /* + * This test program establishes contexts with the krb5 mech, the default +@@ -86,6 +87,9 @@ main(int argc, char *argv[]) + gss_krb5_lucid_context_v1_t *ilucid, *alucid; + gss_krb5_rfc1964_keydata_t *i1964, *a1964; + gss_krb5_cfx_keydata_t *icfx, *acfx; ++ gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET; ++ gss_OID ssf_oid = GSS_C_SEC_CONTEXT_SASL_SSF; ++ unsigned int ssf; + size_t count; + void *lptr; + int c; +@@ -139,6 +143,16 @@ main(int argc, char *argv[]) + establish_contexts(&mech_krb5, icred, acred, tname, flags, &ictx, &actx, + NULL, NULL, NULL); + ++ /* Query the SSF value and range-check the result. */ ++ major = gss_inquire_sec_context_by_oid(&minor, ictx, ssf_oid, &bufset); ++ check_gsserr("gss_inquire_sec_context_by_oid(ssf)", major, minor); ++ if (bufset->elements[0].length != 4) ++ errout("SSF buffer has unexpected length"); ++ ssf = load_32_be(bufset->elements[0].value); ++ if (ssf < 56 || ssf > 256) ++ errout("SSF value not within acceptable range (56-256)"); ++ (void)gss_release_buffer_set(&minor, &bufset); ++ + /* Export to lucid contexts. */ + major = gss_krb5_export_lucid_sec_context(&minor, &ictx, 1, &lptr); + check_gsserr("gss_export_lucid_sec_context(initiator)", major, minor); diff --git a/SOURCES/Add-test-cert-generation-to-make-certs.sh.patch b/SOURCES/Add-test-cert-generation-to-make-certs.sh.patch new file mode 100644 index 0000000..9c1dcf9 --- /dev/null +++ b/SOURCES/Add-test-cert-generation-to-make-certs.sh.patch @@ -0,0 +1,92 @@ +From fd8ce9e1ed7a8d6cf5ac7d27d6acf40b0453c45e Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 5 Sep 2017 15:54:31 -0400 +Subject: [PATCH] Add test cert generation to make-certs.sh + +Based on commit 5a1d0388ba2e4ec510ed715ce5fbc7f748941425 but missing +everything but the make-certs change since infrastructure cannot patch +binaries. Plan to run make-certs during build, but this will only +work with openssl < 1.1. + +Signed-off-by: Robbie Harwood +--- + src/tests/dejagnu/pkinit-certs/make-certs.sh | 53 +++++++++++++++++++++++++++- + 1 file changed, 52 insertions(+), 1 deletion(-) + +diff --git a/src/tests/dejagnu/pkinit-certs/make-certs.sh b/src/tests/dejagnu/pkinit-certs/make-certs.sh +index b82ef6f83..0f07709b0 100755 +--- a/src/tests/dejagnu/pkinit-certs/make-certs.sh ++++ b/src/tests/dejagnu/pkinit-certs/make-certs.sh +@@ -4,7 +4,9 @@ NAMETYPE=1 + KEYSIZE=2048 + DAYS=4000 + REALM=KRBTEST.COM ++LOWREALM=krbtest.com + KRB5_PRINCIPAL_SAN=1.3.6.1.5.2.2 ++KRB5_UPN_SAN=1.3.6.1.4.1.311.20.2.3 + PKINIT_KDC_EKU=1.3.6.1.5.2.3.5 + PKINIT_CLIENT_EKU=1.3.6.1.5.2.3.4 + TLS_SERVER_EKU=1.3.6.1.5.5.7.3.1 +@@ -85,6 +87,30 @@ keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement + basicConstraints = critical,CA:FALSE + subjectAltName = otherName:$KRB5_PRINCIPAL_SAN;SEQUENCE:krb5princ_client + extendedKeyUsage = $CLIENT_EKU_LIST ++ ++[exts_upn_client] ++subjectKeyIdentifier = hash ++authorityKeyIdentifier = keyid:always,issuer:always ++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement ++basicConstraints = critical,CA:FALSE ++subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user@$LOWREALM ++extendedKeyUsage = $CLIENT_EKU_LIST ++ ++[exts_upn2_client] ++subjectKeyIdentifier = hash ++authorityKeyIdentifier = keyid:always,issuer:always ++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement ++basicConstraints = critical,CA:FALSE ++subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user ++extendedKeyUsage = $CLIENT_EKU_LIST ++ ++[exts_upn3_client] ++subjectKeyIdentifier = hash ++authorityKeyIdentifier = keyid:always,issuer:always ++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement ++basicConstraints = critical,CA:FALSE ++subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user@$REALM ++extendedKeyUsage = $CLIENT_EKU_LIST + EOF + + # Generate a private key. +@@ -113,5 +139,30 @@ openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user.p12 \ + openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user-enc.p12 \ + -passout pass:encrypted + ++# Generate a client certificate and PKCS#12 bundles with a UPN SAN. ++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ ++ -key privkey.pem -out user-upn.csr ++SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn_client \ ++ -set_serial 4 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ ++ -out user-upn.pem -in user-upn.csr ++openssl pkcs12 -export -in user-upn.pem -inkey privkey.pem -out user-upn.p12 \ ++ -passout pass: ++ ++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ ++ -key privkey.pem -out user-upn2.csr ++SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn2_client \ ++ -set_serial 5 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ ++ -out user-upn2.pem -in user-upn2.csr ++openssl pkcs12 -export -in user-upn2.pem -inkey privkey.pem \ ++ -out user-upn2.p12 -passout pass: ++ ++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ ++ -key privkey.pem -out user-upn3.csr ++SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn3_client \ ++ -set_serial 6 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ ++ -out user-upn3.pem -in user-upn3.csr ++openssl pkcs12 -export -in user-upn3.pem -inkey privkey.pem \ ++ -out user-upn3.p12 -passout pass: ++ + # Clean up. +-rm -f openssl.cnf kdc.csr user.csr ++rm -f openssl.cnf kdc.csr user.csr user-upn.csr user-upn2.csr user-upn3.csr diff --git a/SOURCES/Add-test-cert-with-no-extensions.patch b/SOURCES/Add-test-cert-with-no-extensions.patch new file mode 100644 index 0000000..90201f1 --- /dev/null +++ b/SOURCES/Add-test-cert-with-no-extensions.patch @@ -0,0 +1,36 @@ +From dd189f46b9e43392b842c4309c95dc7e71963261 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Thu, 5 Oct 2017 12:54:13 -0400 +Subject: [PATCH] Add test cert with no extensions + +Add commands to make-certs.sh to generate a test client certificate +with no certificate extensions. Re-run make-certs.sh. + +ticket: 8562 +(cherry-picked from commit 0d23835660ab131d244d395e4568969b5c0dc678) +[rharwood@redhat.com: only backport the make-certs.sh changes] + +Signed-off-by: Robbie Harwood +--- + src/tests/dejagnu/pkinit-certs/make-certs.sh | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/tests/dejagnu/pkinit-certs/make-certs.sh b/src/tests/dejagnu/pkinit-certs/make-certs.sh +index 0d8c2019a..23426af8a 100755 +--- a/src/tests/dejagnu/pkinit-certs/make-certs.sh ++++ b/src/tests/dejagnu/pkinit-certs/make-certs.sh +@@ -163,5 +163,14 @@ SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn3_client \ + openssl pkcs12 -export -in user-upn3.pem -inkey privkey.pem \ + -out user-upn3.p12 -passout pass: + ++# Generate a client certificate and PKCS#12 bundle with no PKINIT extensions. ++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ ++ -key privkey.pem -out generic.csr ++SUBJECT=user openssl x509 -set_serial 7 -days $DAYS -req -CA ca.pem \ ++ -CAkey privkey.pem -out generic.pem -in generic.csr ++openssl pkcs12 -export -in generic.pem -inkey privkey.pem -out generic.p12 \ ++ -passout pass: ++ + # Clean up. + rm -f openssl.cnf kdc.csr user.csr user-upn.csr user-upn2.csr user-upn3.csr ++rm -f generic.csr diff --git a/SOURCES/Add-the-client_name-kdcpreauth-callback.patch b/SOURCES/Add-the-client_name-kdcpreauth-callback.patch index 7cd1b67..25f4dea 100644 --- a/SOURCES/Add-the-client_name-kdcpreauth-callback.patch +++ b/SOURCES/Add-the-client_name-kdcpreauth-callback.patch @@ -1,4 +1,4 @@ -From b0f389ad69cbd68f2825fe32556e4b4a599a0ac3 Mon Sep 17 00:00:00 2001 +From aa153bb60c4fdc05adbc88cca578612fce6c8ce0 Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Tue, 4 Apr 2017 16:54:56 -0400 Subject: [PATCH] Add the client_name() kdcpreauth callback @@ -7,6 +7,7 @@ Add a kdcpreauth callback to returns the canonicalized client principal. ticket: 8570 (new) (cherry picked from commit a84f39ec30f3deeda7836da6e8b3d8dcf7a045b1) +Signed-off-by: Robbie Harwood --- src/include/krb5/kdcpreauth_plugin.h | 6 ++++++ src/kdc/kdc_preauth.c | 9 ++++++++- diff --git a/SOURCES/Add-timestamp-helper-functions.patch b/SOURCES/Add-timestamp-helper-functions.patch new file mode 100644 index 0000000..1bd6a8e --- /dev/null +++ b/SOURCES/Add-timestamp-helper-functions.patch @@ -0,0 +1,81 @@ +From 6437685130b68670888db1d0551f5464d56c4cec Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Sat, 22 Apr 2017 09:49:12 -0400 +Subject: [PATCH] Add timestamp helper functions + +Add k5-int.h helper functions to manipulate krb5_timestamp values, +avoiding undefined behavior and treating negative timestamp values as +times between 2038 and 2106. Add a doxygen comment for krb5_timestamp +indicating how third-party code should use it safely. + +ticket: 8352 +(cherry picked from commit 58e9155060cd93b1a7557e37fbc9b077b76465c2) +Signed-off-by: Robbie Harwood +--- + src/include/k5-int.h | 31 +++++++++++++++++++++++++++++++ + src/include/krb5/krb5.hin | 9 +++++++++ + 2 files changed, 40 insertions(+) + +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index 06ca2b66d..82ee20760 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -2353,6 +2353,37 @@ k5memdup0(const void *in, size_t len, krb5_error_code *code) + return ptr; + } + ++/* Convert a krb5_timestamp to a time_t value, treating the negative range of ++ * krb5_timestamp as times between 2038 and 2106 (if time_t is 64-bit). */ ++static inline time_t ++ts2tt(krb5_timestamp timestamp) ++{ ++ return (time_t)(uint32_t)timestamp; ++} ++ ++/* Return the delta between two timestamps (a - b) as a signed 32-bit value, ++ * without relying on undefined behavior. */ ++static inline krb5_deltat ++ts_delta(krb5_timestamp a, krb5_timestamp b) ++{ ++ return (krb5_deltat)((uint32_t)a - (uint32_t)b); ++} ++ ++/* Increment a timestamp by a signed 32-bit interval, without relying on ++ * undefined behavior. */ ++static inline krb5_timestamp ++ts_incr(krb5_timestamp ts, krb5_deltat delta) ++{ ++ return (krb5_timestamp)((uint32_t)ts + (uint32_t)delta); ++} ++ ++/* Return true if a comes after b. */ ++static inline krb5_boolean ++ts_after(krb5_timestamp a, krb5_timestamp b) ++{ ++ return (uint32_t)a > (uint32_t)b; ++} ++ + krb5_error_code KRB5_CALLCONV + krb5_get_credentials_for_user(krb5_context context, krb5_flags options, + krb5_ccache ccache, +diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin +index cf60d6c41..53ad85384 100644 +--- a/src/include/krb5/krb5.hin ++++ b/src/include/krb5/krb5.hin +@@ -187,7 +187,16 @@ typedef krb5_int32 krb5_cryptotype; + + typedef krb5_int32 krb5_preauthtype; /* This may change, later on */ + typedef krb5_int32 krb5_flags; ++ ++/** ++ * Represents a timestamp in seconds since the POSIX epoch. This legacy type ++ * is used frequently in the ABI, but cannot represent timestamps after 2038 as ++ * a positive number. Code which uses this type should cast values of it to ++ * uint32_t so that negative values are treated as timestamps between 2038 and ++ * 2106 on platforms with 64-bit time_t. ++ */ + typedef krb5_int32 krb5_timestamp; ++ + typedef krb5_int32 krb5_deltat; + + /** diff --git a/SOURCES/Add-timestamp-tests.patch b/SOURCES/Add-timestamp-tests.patch new file mode 100644 index 0000000..4fe37aa --- /dev/null +++ b/SOURCES/Add-timestamp-tests.patch @@ -0,0 +1,600 @@ +From 47999bb8735f653f06e0eb46e7eced600210b9da Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Sat, 29 Apr 2017 17:30:36 -0400 +Subject: [PATCH] Add timestamp tests + +Add a test program for krb5int_validate_times() covering cases before +and across the y2038 boundary. Add a GSSAPI test program to exercise +lifetime queries, and tests using it in t_gssapi.py for ticket end +times after y2038. Add a new test script t_y2038.py which only runs +on platforms with 64-bit time_t to exercise end-user operations across +and after y2038. Add an LDAP test case to test storage of post-y2038 +timestamps. + +ticket: 8352 +(cherry picked from commit 8ca62e54e89e2fbd6a089e8ab20b4e374a486003) +[rharwood@redhat.com: prune gitignore] +Signed-off-by: Robbie Harwood +--- + src/Makefile.in | 1 + + src/config/pre.in | 2 + + src/configure.in | 3 + + src/lib/krb5/krb/Makefile.in | 14 ++-- + src/lib/krb5/krb/t_valid_times.c | 109 ++++++++++++++++++++++++++++++ + src/tests/Makefile.in | 1 + + src/tests/gssapi/Makefile.in | 27 ++++---- + src/tests/gssapi/t_gssapi.py | 32 +++++++++ + src/tests/gssapi/t_lifetime.c | 140 +++++++++++++++++++++++++++++++++++++++ + src/tests/t_kdb.py | 7 ++ + src/tests/t_y2038.py | 75 +++++++++++++++++++++ + 11 files changed, 395 insertions(+), 16 deletions(-) + create mode 100644 src/lib/krb5/krb/t_valid_times.c + create mode 100644 src/tests/gssapi/t_lifetime.c + create mode 100644 src/tests/t_y2038.py + +diff --git a/src/Makefile.in b/src/Makefile.in +index b0249778c..ad8565056 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -521,6 +521,7 @@ pyrunenv.vals: Makefile + done > $@ + echo "tls_impl = '$(TLS_IMPL)'" >> $@ + echo "have_sasl = '$(HAVE_SASL)'" >> $@ ++ echo "sizeof_time_t = $(SIZEOF_TIME_T)" >> $@ + + runenv.py: pyrunenv.vals + echo 'env = {}' > $@ +diff --git a/src/config/pre.in b/src/config/pre.in +index d961b5621..f23c07d9d 100644 +--- a/src/config/pre.in ++++ b/src/config/pre.in +@@ -452,6 +452,8 @@ HAVE_SASL = @HAVE_SASL@ + # Whether we have libresolv 1.1.5 for URI discovery tests + HAVE_RESOLV_WRAPPER = @HAVE_RESOLV_WRAPPER@ + ++SIZEOF_TIME_T = @SIZEOF_TIME_T@ ++ + # error table rules + # + ### /* these are invoked as $(...) foo.et, which works, but could be better */ +diff --git a/src/configure.in b/src/configure.in +index 24f653f0d..4ae2c07d5 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -744,6 +744,9 @@ fi + + AC_HEADER_TIME + AC_CHECK_TYPE(time_t, long) ++AC_CHECK_SIZEOF(time_t) ++SIZEOF_TIME_T=$ac_cv_sizeof_time_t ++AC_SUBST(SIZEOF_TIME_T) + + # Determine where to put the replay cache. + +diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in +index 0fe02a95d..55f82b147 100644 +--- a/src/lib/krb5/krb/Makefile.in ++++ b/src/lib/krb5/krb/Makefile.in +@@ -364,6 +364,7 @@ SRCS= $(srcdir)/addr_comp.c \ + $(srcdir)/t_in_ccache.c \ + $(srcdir)/t_response_items.c \ + $(srcdir)/t_sname_match.c \ ++ $(srcdir)/t_valid_times.c \ + $(srcdir)/t_vfy_increds.c + + # Someday, when we have a "maintainer mode", do this right: +@@ -457,9 +458,12 @@ t_response_items: t_response_items.o response_items.o $(KRB5_BASE_DEPLIBS) + t_sname_match: t_sname_match.o sname_match.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o $@ t_sname_match.o sname_match.o $(KRB5_BASE_LIBS) + ++t_valid_times: t_valid_times.o valid_times.o $(KRB5_BASE_DEPLIBS) ++ $(CC_LINK) -o $@ t_valid_times.o valid_times.o $(KRB5_BASE_LIBS) ++ + TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand t_authdata t_pac \ +- t_in_ccache t_cc_config t_copy_context \ +- t_princ t_etypes t_vfy_increds t_response_items t_sname_match ++ t_in_ccache t_cc_config t_copy_context t_princ t_etypes t_vfy_increds \ ++ t_response_items t_sname_match t_valid_times + + check-unix: $(TEST_PROGS) + $(RUN_TEST_LOCAL_CONF) ./t_kerb \ +@@ -496,6 +500,7 @@ check-unix: $(TEST_PROGS) + $(RUN_TEST) ./t_response_items + $(RUN_TEST) ./t_copy_context + $(RUN_TEST) ./t_sname_match ++ $(RUN_TEST) ./t_valid_times + + check-pytests: t_expire_warn t_vfy_increds + $(RUNPYTEST) $(srcdir)/t_expire_warn.py $(PYTESTFLAGS) +@@ -522,8 +527,9 @@ clean: + $(OUTPRE)t_ad_fx_armor$(EXEEXT) $(OUTPRE)t_ad_fx_armor.$(OBJEXT) \ + $(OUTPRE)t_vfy_increds$(EXEEXT) $(OUTPRE)t_vfy_increds.$(OBJEXT) \ + $(OUTPRE)t_response_items$(EXEEXT) \ +- $(OUTPRE)t_response_items.$(OBJEXT) $(OUTPRE)t_sname_match$(EXEEXT) \ +- $(OUTPRE)t_sname_match.$(OBJEXT) \ ++ $(OUTPRE)t_response_items.$(OBJEXT) \ ++ $(OUTPRE)t_sname_match$(EXEEXT) $(OUTPRE)t_sname_match.$(OBJEXT) \ ++ $(OUTPRE)t_valid_times$(EXEEXT) $(OUTPRE)t_valid_times.$(OBJECT) \ + $(OUTPRE)t_parse_host_string$(EXEEXT) \ + $(OUTPRE)t_parse_host_string.$(OBJEXT) + +diff --git a/src/lib/krb5/krb/t_valid_times.c b/src/lib/krb5/krb/t_valid_times.c +new file mode 100644 +index 000000000..1b469ffc2 +--- /dev/null ++++ b/src/lib/krb5/krb/t_valid_times.c +@@ -0,0 +1,109 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* lib/krb5/krb/t_valid_times.c - test program for krb5int_validate_times() */ ++/* ++ * Copyright (C) 2017 by the Massachusetts Institute of Technology. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "k5-int.h" ++#include "int-proto.h" ++ ++#define BOUNDARY (uint32_t)INT32_MIN ++ ++int ++main() ++{ ++ krb5_error_code ret; ++ krb5_context context; ++ krb5_ticket_times times = { 0, 0, 0, 0 }; ++ ++ ret = krb5_init_context(&context); ++ assert(!ret); ++ ++ /* Current time is within authtime and end time. */ ++ ret = krb5_set_debugging_time(context, 1000, 0); ++ times.authtime = 500; ++ times.endtime = 1500; ++ ret = krb5int_validate_times(context, ×); ++ assert(!ret); ++ ++ /* Current time is before starttime, but within clock skew. */ ++ times.starttime = 1100; ++ ret = krb5int_validate_times(context, ×); ++ assert(!ret); ++ ++ /* Current time is before starttime by more than clock skew. */ ++ times.starttime = 1400; ++ ret = krb5int_validate_times(context, ×); ++ assert(ret == KRB5KRB_AP_ERR_TKT_NYV); ++ ++ /* Current time is after end time, but within clock skew. */ ++ times.starttime = 500; ++ times.endtime = 800; ++ ret = krb5int_validate_times(context, ×); ++ assert(!ret); ++ ++ /* Current time is after end time by more than clock skew. */ ++ times.endtime = 600; ++ ret = krb5int_validate_times(context, ×); ++ assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED); ++ ++ /* Current time is within starttime and endtime; current time and ++ * endtime are across y2038 boundary. */ ++ ret = krb5_set_debugging_time(context, BOUNDARY - 100, 0); ++ assert(!ret); ++ times.starttime = BOUNDARY - 200; ++ times.endtime = BOUNDARY + 500; ++ ret = krb5int_validate_times(context, ×); ++ assert(!ret); ++ ++ /* Current time is before starttime, but by less than clock skew. */ ++ times.starttime = BOUNDARY + 100; ++ ret = krb5int_validate_times(context, ×); ++ assert(!ret); ++ ++ /* Current time is before starttime by more than clock skew. */ ++ times.starttime = BOUNDARY + 250; ++ ret = krb5int_validate_times(context, ×); ++ assert(ret == KRB5KRB_AP_ERR_TKT_NYV); ++ ++ /* Current time is after endtime, but by less than clock skew. */ ++ ret = krb5_set_debugging_time(context, BOUNDARY + 100, 0); ++ assert(!ret); ++ times.starttime = BOUNDARY - 1000; ++ times.endtime = BOUNDARY - 100; ++ ret = krb5int_validate_times(context, ×); ++ assert(!ret); ++ ++ /* Current time is after endtime by more than clock skew. */ ++ times.endtime = BOUNDARY - 300; ++ ret = krb5int_validate_times(context, ×); ++ assert(ret == KRB5KRB_AP_ERR_TKT_EXPIRED); ++ ++ return 0; ++} +diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in +index 0e93d6b59..2b3112537 100644 +--- a/src/tests/Makefile.in ++++ b/src/tests/Makefile.in +@@ -168,6 +168,7 @@ check-pytests: localauth plugorder rdreq responder s2p s4u2proxy unlockiter + $(RUNPYTEST) $(srcdir)/t_princflags.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_tabdump.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_certauth.py $(PYTESTFLAGS) ++ $(RUNPYTEST) $(srcdir)/t_y2038.py $(PYTESTFLAGS) + + clean: + $(RM) adata etinfo forward gcred hist hooks hrealm icred kdbtest +diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in +index 6c1464297..604f926de 100644 +--- a/src/tests/gssapi/Makefile.in ++++ b/src/tests/gssapi/Makefile.in +@@ -15,15 +15,16 @@ SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \ + $(srcdir)/t_gssexts.c $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c \ + $(srcdir)/t_invalid.c $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \ + $(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \ +- $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c $(srcdir)/t_pcontok.c \ +- $(srcdir)/t_prf.c $(srcdir)/t_s4u.c $(srcdir)/t_s4u2proxy_krb5.c \ +- $(srcdir)/t_saslname.c $(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c ++ $(srcdir)/t_lifetime.c $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c \ ++ $(srcdir)/t_pcontok.c $(srcdir)/t_prf.c $(srcdir)/t_s4u.c \ ++ $(srcdir)/t_s4u2proxy_krb5.c $(srcdir)/t_saslname.c \ ++ $(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c + + OBJS= ccinit.o ccrefresh.o common.o t_accname.o t_ccselect.o t_ciflags.o \ + t_credstore.o t_enctypes.o t_err.o t_export_cred.o t_export_name.o \ + t_gssexts.o t_imp_cred.o t_imp_name.o t_invalid.o t_inq_cred.o \ +- t_inq_ctx.o t_inq_mechs_name.o t_iov.o t_namingexts.o t_oid.o \ +- t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \ ++ t_inq_ctx.o t_inq_mechs_name.o t_iov.o t_lifetime.o t_namingexts.o \ ++ t_oid.o t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \ + t_spnego.o t_srcattrs.o + + COMMON_DEPS= common.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS) +@@ -31,9 +32,9 @@ COMMON_LIBS= common.o $(GSS_LIBS) $(KRB5_BASE_LIBS) + + all: ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore t_enctypes \ + t_err t_export_cred t_export_name t_gssexts t_imp_cred t_imp_name \ +- t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_namingexts \ +- t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname t_spnego \ +- t_srcattrs ++ t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime \ ++ t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname \ ++ t_spnego t_srcattrs + + check-unix: t_oid + $(RUN_TEST) ./t_invalid +@@ -42,8 +43,8 @@ check-unix: t_oid + + check-pytests: ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore \ + t_enctypes t_err t_export_cred t_export_name t_imp_cred t_inq_cred \ +- t_inq_ctx t_inq_mechs_name t_iov t_pcontok t_s4u t_s4u2proxy_krb5 \ +- t_spnego t_srcattrs ++ t_inq_ctx t_inq_mechs_name t_iov t_lifetime t_pcontok t_s4u \ ++ t_s4u2proxy_krb5 t_spnego t_srcattrs + $(RUNPYTEST) $(srcdir)/t_gssapi.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_ccselect.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_client_keytab.py $(PYTESTFLAGS) +@@ -88,6 +89,8 @@ t_inq_mechs_name: t_inq_mechs_name.o $(COMMON_DEPS) + $(CC_LINK) -o $@ t_inq_mechs_name.o $(COMMON_LIBS) + t_iov: t_iov.o $(COMMON_DEPS) + $(CC_LINK) -o $@ t_iov.o $(COMMON_LIBS) ++t_lifetime: t_lifetime.o $(COMMON_DEPS) ++ $(CC_LINK) -o $@ t_lifetime.o $(COMMON_LIBS) + t_namingexts: t_namingexts.o $(COMMON_DEPS) + $(CC_LINK) -o $@ t_namingexts.o $(COMMON_LIBS) + t_pcontok: t_pcontok.o $(COMMON_DEPS) +@@ -111,5 +114,5 @@ clean: + $(RM) ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore + $(RM) t_enctypes t_err t_export_cred t_export_name t_gssexts t_imp_cred + $(RM) t_imp_name t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov +- $(RM) t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 +- $(RM) t_saslname t_spnego t_srcattrs ++ $(RM) t_lifetime t_namingexts t_oid t_pcontok t_prf t_s4u ++ $(RM) t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs +diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py +index e23c936d7..fa214242f 100755 +--- a/src/tests/gssapi/t_gssapi.py ++++ b/src/tests/gssapi/t_gssapi.py +@@ -220,4 +220,36 @@ realm.run(['./t_ciflags', 'p:' + realm.host_princ]) + # contexts. + realm.run(['./t_inq_ctx', 'user', password('user'), 'p:%s' % realm.host_princ]) + ++# Test lifetime results, using a realm with a large maximum lifetime ++# so that we can test ticket end dates after y2038. There are no ++# time_t conversions involved, so we can run these tests on platforms ++# with 32-bit time_t. ++realm.stop() ++conf = {'realms': {'$realm': {'max_life': '9000d'}}} ++realm = K5Realm(kdc_conf=conf, get_creds=False) ++ ++# Check a lifetime string result against an expected number value (or None). ++# Allow some variance due to time elapsed during the tests. ++def check_lifetime(msg, val, expected): ++ if expected is None and val != 'indefinite': ++ fail('%s: expected indefinite, got %s' % (msg, val)) ++ if expected is not None and val == 'indefinite': ++ fail('%s: expected %d, got indefinite' % (msg, expected)) ++ if expected is not None and abs(int(val) - expected) > 100: ++ fail('%s: expected %d, got %s' % (msg, expected, val)) ++ ++realm.kinit(realm.user_princ, password('user'), flags=['-l', '8500d']) ++out = realm.run(['./t_lifetime', 'p:' + realm.host_princ, str(8000 * 86400)]) ++ln = out.split('\n') ++check_lifetime('icred gss_acquire_cred', ln[0], 8500 * 86400) ++check_lifetime('icred gss_inquire_cred', ln[1], 8500 * 86400) ++check_lifetime('acred gss_acquire_cred', ln[2], None) ++check_lifetime('acred gss_inquire_cred', ln[3], None) ++check_lifetime('ictx gss_init_sec_context', ln[4], 8000 * 86400) ++check_lifetime('ictx gss_inquire_context', ln[5], 8000 * 86400) ++check_lifetime('ictx gss_context_time', ln[6], 8000 * 86400) ++check_lifetime('actx gss_accept_sec_context', ln[7], 8000 * 86400 + 300) ++check_lifetime('actx gss_inquire_context', ln[8], 8000 * 86400 + 300) ++check_lifetime('actx gss_context_time', ln[9], 8000 * 86400 + 300) ++ + success('GSSAPI tests') +diff --git a/src/tests/gssapi/t_lifetime.c b/src/tests/gssapi/t_lifetime.c +new file mode 100644 +index 000000000..8dcf18621 +--- /dev/null ++++ b/src/tests/gssapi/t_lifetime.c +@@ -0,0 +1,140 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* tests/gssapi/t_lifetime.c - display cred and context lifetimes */ ++/* ++ * Copyright (C) 2017 by the Massachusetts Institute of Technology. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include "common.h" ++ ++/* ++ * Using the default credential, exercise the GSS functions which accept or ++ * produce lifetimes. Display the following results, one per line, as ASCII ++ * integers or the string "indefinite": ++ * ++ * initiator cred lifetime according to gss_acquire_cred() ++ * initiator cred lifetime according to gss_inquire_cred() ++ * acceptor cred lifetime according to gss_acquire_cred() ++ * acceptor cred lifetime according to gss_inquire_cred() ++ * initiator context lifetime according to gss_init_sec_context() ++ * initiator context lifetime according to gss_inquire_context() ++ * initiator context lifetime according to gss_context_time() ++ * acceptor context lifetime according to gss_init_sec_context() ++ * acceptor context lifetime according to gss_inquire_context() ++ * acceptor context lifetime according to gss_context_time() ++ */ ++ ++static void ++display_time(OM_uint32 tval) ++{ ++ if (tval == GSS_C_INDEFINITE) ++ puts("indefinite"); ++ else ++ printf("%u\n", (unsigned int)tval); ++} ++ ++int ++main(int argc, char *argv[]) ++{ ++ OM_uint32 minor, major; ++ gss_cred_id_t icred, acred; ++ gss_name_t tname; ++ gss_ctx_id_t ictx = GSS_C_NO_CONTEXT, actx = GSS_C_NO_CONTEXT; ++ gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 time_req = GSS_C_INDEFINITE, time_rec; ++ ++ if (argc < 2 || argc > 3) { ++ fprintf(stderr, "Usage: %s targetname [time_req]\n", argv[0]); ++ return 1; ++ } ++ tname = import_name(argv[1]); ++ if (argc >= 3) ++ time_req = atoll(argv[2]); ++ ++ /* Get initiator cred and display its lifetime according to ++ * gss_acquire_cred and gss_inquire_cred. */ ++ major = gss_acquire_cred(&minor, GSS_C_NO_NAME, time_req, &mechset_krb5, ++ GSS_C_INITIATE, &icred, NULL, &time_rec); ++ check_gsserr("gss_acquire_cred(initiate)", major, minor); ++ display_time(time_rec); ++ major = gss_inquire_cred(&minor, icred, NULL, &time_rec, NULL, NULL); ++ check_gsserr("gss_inquire_cred(initiate)", major, minor); ++ display_time(time_rec); ++ ++ /* Get acceptor cred and display its lifetime according to gss_acquire_cred ++ * and gss_inquire_cred. */ ++ major = gss_acquire_cred(&minor, GSS_C_NO_NAME, time_req, &mechset_krb5, ++ GSS_C_ACCEPT, &acred, NULL, &time_rec); ++ check_gsserr("gss_acquire_cred(accept)", major, minor); ++ display_time(time_rec); ++ major = gss_inquire_cred(&minor, acred, NULL, &time_rec, NULL, NULL); ++ check_gsserr("gss_inquire_cred(accept)", major, minor); ++ display_time(time_rec); ++ ++ /* Make an initiator context and display its lifetime according to ++ * gss_init_sec_context, gss_inquire_context, and gss_context_time. */ ++ major = gss_init_sec_context(&minor, icred, &ictx, tname, &mech_krb5, 0, ++ time_req, GSS_C_NO_CHANNEL_BINDINGS, &atok, ++ NULL, &itok, NULL, &time_rec); ++ check_gsserr("gss_init_sec_context", major, minor); ++ assert(major == GSS_S_COMPLETE); ++ display_time(time_rec); ++ major = gss_inquire_context(&minor, ictx, NULL, NULL, &time_rec, NULL, ++ NULL, NULL, NULL); ++ check_gsserr("gss_inquire_context(initiate)", major, minor); ++ display_time(time_rec); ++ major = gss_context_time(&minor, ictx, &time_rec); ++ check_gsserr("gss_context_time(initiate)", major, minor); ++ display_time(time_rec); ++ ++ major = gss_accept_sec_context(&minor, &actx, acred, &itok, ++ GSS_C_NO_CHANNEL_BINDINGS, NULL, ++ NULL, &atok, NULL, &time_rec, NULL); ++ check_gsserr("gss_accept_sec_context", major, minor); ++ assert(major == GSS_S_COMPLETE); ++ display_time(time_rec); ++ major = gss_inquire_context(&minor, actx, NULL, NULL, &time_rec, NULL, ++ NULL, NULL, NULL); ++ check_gsserr("gss_inquire_context(accept)", major, minor); ++ display_time(time_rec); ++ major = gss_context_time(&minor, actx, &time_rec); ++ check_gsserr("gss_context_time(accept)", major, minor); ++ display_time(time_rec); ++ ++ (void)gss_release_buffer(&minor, &itok); ++ (void)gss_release_buffer(&minor, &atok); ++ (void)gss_release_name(&minor, &tname); ++ (void)gss_release_cred(&minor, &icred); ++ (void)gss_release_cred(&minor, &acred); ++ (void)gss_delete_sec_context(&minor, &ictx, NULL); ++ (void)gss_delete_sec_context(&minor, &actx, NULL); ++ return 0; ++} +diff --git a/src/tests/t_kdb.py b/src/tests/t_kdb.py +index 185225afa..c0eeb0118 100755 +--- a/src/tests/t_kdb.py ++++ b/src/tests/t_kdb.py +@@ -446,6 +446,13 @@ realm.run([kadminl, 'addprinc', '-policy', 'keepoldpasspol', '-pw', 'aaaa', + for p in ('bbbb', 'cccc', 'aaaa'): + realm.run([kadminl, 'cpw', '-keepold', '-pw', p, 'keepoldpassprinc']) + ++if runenv.sizeof_time_t <= 4: ++ skipped('y2038 LDAP test', 'platform has 32-bit time_t') ++else: ++ # Test storage of timestamps after y2038. ++ realm.run([kadminl, 'modprinc', '-pwexpire', '2040-02-03', 'user']) ++ realm.run([kadminl, 'getprinc', 'user'], expected_msg=' 2040\n') ++ + realm.stop() + + # Briefly test dump and load. +diff --git a/src/tests/t_y2038.py b/src/tests/t_y2038.py +new file mode 100644 +index 000000000..02e946df4 +--- /dev/null ++++ b/src/tests/t_y2038.py +@@ -0,0 +1,75 @@ ++#!/usr/bin/python ++from k5test import * ++ ++# These tests will become much less important after the y2038 boundary ++# has elapsed, and may start exhibiting problems around the year 2075. ++ ++if runenv.sizeof_time_t <= 4: ++ skip_rest('y2038 timestamp tests', 'platform has 32-bit time_t') ++ ++# Start a KDC running roughly 21 years in the future, after the y2038 ++# boundary. Set long maximum lifetimes for later tests. ++conf = {'realms': {'$realm': {'max_life': '9000d', ++ 'max_renewable_life': '9000d'}}} ++realm = K5Realm(start_kdc=False, kdc_conf=conf) ++realm.start_kdc(['-T', '662256000']) ++ ++# kinit without preauth should succeed with clock skew correction, but ++# will result in an expired ticket, because we sent an absolute end ++# time and didn't get a chance to correct it.. ++realm.kinit(realm.user_princ, password('user')) ++realm.run([kvno, realm.host_princ], expected_code=1, ++ expected_msg='Ticket expired') ++ ++# kinit with preauth should succeed and result in a valid ticket, as ++# we get a chance to correct the end time based on the KDC time. Try ++# with encrypted timestamp and encrypted challenge. ++realm.run([kadminl, 'modprinc', '+requires_preauth', 'user']) ++realm.kinit(realm.user_princ, password('user')) ++realm.run([kvno, realm.host_princ]) ++realm.kinit(realm.user_princ, password('user'), flags=['-T', realm.ccache]) ++realm.run([kvno, realm.host_princ]) ++ ++# Test that expiration warning works after y2038, by setting a ++# password expiration time ten minutes after the KDC time. ++realm.run([kadminl, 'modprinc', '-pwexpire', '662256600 seconds', 'user']) ++out = realm.kinit(realm.user_princ, password('user')) ++if 'will expire in less than one hour' not in out: ++ fail('password expiration message') ++year = int(out.split()[-1]) ++if year < 2038 or year > 9999: ++ fail('password expiration year') ++ ++realm.stop_kdc() ++realm.start_kdc() ++realm.start_kadmind() ++realm.prep_kadmin() ++ ++# Test getdate parsing of absolute timestamps after 2038 and ++# marshalling over the kadmin protocol. The local time zone will ++# affect the display time by a little bit, so just look for the year. ++realm.run_kadmin(['modprinc', '-pwexpire', '2040-02-03', realm.host_princ]) ++realm.run_kadmin(['getprinc', realm.host_princ], expected_msg=' 2040\n') ++ ++# Get a ticket whose lifetime crosses the y2038 boundary and ++# range-check the expiration year as reported by klist. ++realm.kinit(realm.user_princ, password('user'), ++ flags=['-l', '8000d', '-r', '8500d']) ++realm.run([kvno, realm.host_princ]) ++out = realm.run([klist]) ++if int(out.split('\n')[4].split()[2].split('/')[2]) < 39: ++ fail('unexpected tgt expiration year') ++if int(out.split('\n')[5].split()[2].split('/')[2]) < 40: ++ fail('unexpected tgt rtill year') ++if int(out.split('\n')[6].split()[2].split('/')[2]) < 39: ++ fail('unexpected service ticket expiration year') ++if int(out.split('\n')[7].split()[2].split('/')[2]) < 40: ++ fail('unexpected service ticket rtill year') ++realm.kinit(realm.user_princ, None, ['-R']) ++out = realm.run([klist]) ++if int(out.split('\n')[4].split()[2].split('/')[2]) < 39: ++ fail('unexpected renewed tgt expiration year') ++if int(out.split('\n')[5].split()[2].split('/')[2]) < 40: ++ fail('unexpected renewed tgt rtill year') ++ ++success('y2038 tests') diff --git a/SOURCES/Add-y2038-documentation.patch b/SOURCES/Add-y2038-documentation.patch new file mode 100644 index 0000000..01642e1 --- /dev/null +++ b/SOURCES/Add-y2038-documentation.patch @@ -0,0 +1,60 @@ +From f9702eabc568679f48ea5d0bc7be073582cc52ad Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Thu, 4 May 2017 17:03:35 -0400 +Subject: [PATCH] Add y2038 documentation + +ticket: 8352 +(cherry picked from commit 85d64c43dbf7a7faa56a1999494cdfa49e8bd2c9) +Signed-off-by: Robbie Harwood +--- + doc/appdev/index.rst | 1 + + doc/appdev/y2038.rst | 28 ++++++++++++++++++++++++++++ + 2 files changed, 29 insertions(+) + create mode 100644 doc/appdev/y2038.rst + +diff --git a/doc/appdev/index.rst b/doc/appdev/index.rst +index 3d62045ca..961bb1e9e 100644 +--- a/doc/appdev/index.rst ++++ b/doc/appdev/index.rst +@@ -5,6 +5,7 @@ For application developers + :maxdepth: 1 + + gssapi.rst ++ y2038.rst + h5l_mit_apidiff.rst + init_creds.rst + princ_handle.rst +diff --git a/doc/appdev/y2038.rst b/doc/appdev/y2038.rst +new file mode 100644 +index 000000000..bc4122dad +--- /dev/null ++++ b/doc/appdev/y2038.rst +@@ -0,0 +1,28 @@ ++Year 2038 considerations for uses of krb5_timestamp ++=================================================== ++ ++POSIX time values, which measure the number of seconds since January 1 ++1970, will exceed the maximum value representable in a signed 32-bit ++integer in January 2038. This documentation describes considerations ++for consumers of the MIT krb5 libraries. ++ ++Applications or libraries which use libkrb5 and consume the timestamps ++included in credentials or other structures make use of the ++:c:type:`krb5_timestamp` type. For historical reasons, krb5_timestamp ++is a signed 32-bit integer, even on platforms where a larger type is ++natively used to represent time values. To behave properly for time ++values after January 2038, calling code should cast krb5_timestamp ++values to uint32_t, and then to time_t:: ++ ++ (time_t)(uint32_t)timestamp ++ ++Used in this way, krb5_timestamp values can represent time values up ++until February 2106, provided that the platform uses a 64-bit or ++larger time_t type. This usage will also remain safe if a later ++version of MIT krb5 changes krb5_timestamp to an unsigned 32-bit ++integer. ++ ++The GSSAPI only uses representations of time intervals, not absolute ++times. Callers of the GSSAPI should require no changes to behave ++correctly after January 2038, provided that they use MIT krb5 release ++1.16 or later. diff --git a/SOURCES/Allow-clock-skew-in-krb5-gss_context_time.patch b/SOURCES/Allow-clock-skew-in-krb5-gss_context_time.patch new file mode 100644 index 0000000..8eb9c2e --- /dev/null +++ b/SOURCES/Allow-clock-skew-in-krb5-gss_context_time.patch @@ -0,0 +1,37 @@ +From 498b43b1a58795773834c1c5bb2b61dd801b9a03 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Sat, 22 Apr 2017 16:51:23 -0400 +Subject: [PATCH] Allow clock skew in krb5 gss_context_time() + +Commit b496ce4095133536e0ace36b74130e4b9ecb5e11 (ticket #8268) adds +the clock skew to krb5 acceptor context lifetimes for +gss_accept_sec_context() and gss_inquire_context(), but not for +gss_context_time(). Add the clock skew in gss_context_time() as well. + +ticket: 8581 (new) +target_version: 1.14-next +target_version: 1.15-next +tags: pullup + +(cherry picked from commit b0a072e6431261734e7350996a363801f180e8ea) +Signed-off-by: Robbie Harwood +--- + src/lib/gssapi/krb5/context_time.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c +index a18cfb05b..450593288 100644 +--- a/src/lib/gssapi/krb5/context_time.c ++++ b/src/lib/gssapi/krb5/context_time.c +@@ -51,7 +51,10 @@ krb5_gss_context_time(minor_status, context_handle, time_rec) + return(GSS_S_FAILURE); + } + +- if ((lifetime = ctx->krb_times.endtime - now) <= 0) { ++ lifetime = ctx->krb_times.endtime - now; ++ if (!ctx->initiate) ++ lifetime += ctx->k5_context->clockskew; ++ if (lifetime <= 0) { + *time_rec = 0; + *minor_status = 0; + return(GSS_S_CONTEXT_EXPIRED); diff --git a/SOURCES/Convert-some-pkiDebug-messages-to-TRACE-macros.patch b/SOURCES/Convert-some-pkiDebug-messages-to-TRACE-macros.patch new file mode 100644 index 0000000..69f99cb --- /dev/null +++ b/SOURCES/Convert-some-pkiDebug-messages-to-TRACE-macros.patch @@ -0,0 +1,424 @@ +From b4c2212ae7412e21f4965acdb8c10e4a60b65b9b Mon Sep 17 00:00:00 2001 +From: Matt Rogers +Date: Wed, 29 Mar 2017 10:35:13 -0400 +Subject: [PATCH] Convert some pkiDebug messages to TRACE macros + +ticket: 8568 (new) +(cherry picked from commit 9852862a83952a94300adfafa3e333f43396ec33) +(cherry picked from commit 686fa6476eb759532d566794fa8d430774d44cf7) +Signed-off-by: Robbie Harwood +--- + src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 46 ++++++--------- + src/plugins/preauth/pkinit/pkinit_identity.c | 3 - + src/plugins/preauth/pkinit/pkinit_matching.c | 1 + + src/plugins/preauth/pkinit/pkinit_srv.c | 24 ++++---- + src/plugins/preauth/pkinit/pkinit_trace.h | 68 +++++++++++++++++++++- + 5 files changed, 97 insertions(+), 45 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index 90c30dbf5..70e230ec2 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -2320,7 +2320,6 @@ crypto_check_cert_eku(krb5_context context, + + X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert), + buf, sizeof(buf)); +- pkiDebug("%s: looking for EKUs in cert = %s\n", __FUNCTION__, buf); + + if ((i = X509_get_ext_by_NID(reqctx->received_cert, + NID_ext_key_usage, -1)) >= 0) { +@@ -2354,7 +2353,6 @@ crypto_check_cert_eku(krb5_context context, + + if (found_eku) { + ASN1_BIT_STRING *usage = NULL; +- pkiDebug("%s: found acceptable EKU, checking for digitalSignature\n", __FUNCTION__); + + /* check that digitalSignature KeyUsage is present */ + X509_check_ca(reqctx->received_cert); +@@ -2363,12 +2361,10 @@ crypto_check_cert_eku(krb5_context context, + + if (!ku_reject(reqctx->received_cert, + X509v3_KU_DIGITAL_SIGNATURE)) { +- pkiDebug("%s: found digitalSignature KU\n", +- __FUNCTION__); ++ TRACE_PKINIT_EKU(context); + *valid_eku = 1; + } else +- pkiDebug("%s: didn't find digitalSignature KU\n", +- __FUNCTION__); ++ TRACE_PKINIT_EKU_NO_KU(context); + } + ASN1_BIT_STRING_free(usage); + } +@@ -4317,8 +4313,7 @@ pkinit_get_certs_pkcs12(krb5_context context, + + fp = fopen(idopts->cert_filename, "rb"); + if (fp == NULL) { +- pkiDebug("Failed to open PKCS12 file '%s', error %d\n", +- idopts->cert_filename, errno); ++ TRACE_PKINIT_PKCS_OPEN_FAIL(context, idopts->cert_filename, errno); + goto cleanup; + } + set_cloexec_file(fp); +@@ -4326,8 +4321,7 @@ pkinit_get_certs_pkcs12(krb5_context context, + p12 = d2i_PKCS12_fp(fp, NULL); + fclose(fp); + if (p12 == NULL) { +- pkiDebug("Failed to decode PKCS12 file '%s' contents\n", +- idopts->cert_filename); ++ TRACE_PKINIT_PKCS_DECODE_FAIL(context, idopts->cert_filename); + goto cleanup; + } + /* +@@ -4345,7 +4339,7 @@ pkinit_get_certs_pkcs12(krb5_context context, + char *p12name = reassemble_pkcs12_name(idopts->cert_filename); + const char *tmp; + +- pkiDebug("Initial PKCS12_parse with no password failed\n"); ++ TRACE_PKINIT_PKCS_PARSE_FAIL_FIRST(context); + + if (id_cryptoctx->defer_id_prompt) { + /* Supply the identity name to be passed to the responder. */ +@@ -4386,14 +4380,14 @@ pkinit_get_certs_pkcs12(krb5_context context, + NULL, NULL, 1, &kprompt); + k5int_set_prompt_types(context, 0); + if (r) { +- pkiDebug("Failed to prompt for PKCS12 password"); ++ TRACE_PKINIT_PKCS_PROMPT_FAIL(context); + goto cleanup; + } + } + + ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL); + if (ret == 0) { +- pkiDebug("Second PKCS12_parse with password failed\n"); ++ TRACE_PKINIT_PKCS_PARSE_FAIL_SECOND(context); + goto cleanup; + } + } +@@ -4516,8 +4510,7 @@ pkinit_get_certs_fs(krb5_context context, + } + + if (idopts->key_filename == NULL) { +- pkiDebug("%s: failed to get user's private key location\n", +- __FUNCTION__); ++ TRACE_PKINIT_NO_PRIVKEY(context); + goto cleanup; + } + +@@ -4545,8 +4538,7 @@ pkinit_get_certs_dir(krb5_context context, + char *dirname, *suf; + + if (idopts->cert_filename == NULL) { +- pkiDebug("%s: failed to get user's certificate directory location\n", +- __FUNCTION__); ++ TRACE_PKINIT_NO_CERT(context); + return ENOENT; + } + +@@ -4590,8 +4582,7 @@ pkinit_get_certs_dir(krb5_context context, + retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx, + certname, keyname, i); + if (retval == 0) { +- pkiDebug("%s: Successfully loaded cert (and key) for %s\n", +- __FUNCTION__, dentry->d_name); ++ TRACE_PKINIT_LOADED_CERT(context, dentry->d_name); + i++; + } + else +@@ -4599,8 +4590,7 @@ pkinit_get_certs_dir(krb5_context context, + } + + if (!id_cryptoctx->defer_id_prompt && i == 0) { +- pkiDebug("%s: No cert/key pairs found in directory '%s'\n", +- __FUNCTION__, idopts->cert_filename); ++ TRACE_PKINIT_NO_CERT_AND_KEY(context, idopts->cert_filename); + retval = ENOENT; + goto cleanup; + } +@@ -5370,9 +5360,7 @@ crypto_cert_select_default(krb5_context context, + goto errout; + } + if (cert_count != 1) { +- pkiDebug("%s: ERROR: There are %d certs to choose from, " +- "but there must be exactly one.\n", +- __FUNCTION__, cert_count); ++ TRACE_PKINIT_NO_DEFAULT_CERT(context, cert_count); + retval = EINVAL; + goto errout; + } +@@ -5520,7 +5508,7 @@ load_cas_and_crls(krb5_context context, + switch(catype) { + case CATYPE_ANCHORS: + if (sk_X509_num(ca_certs) == 0) { +- pkiDebug("no anchors in file, %s\n", filename); ++ TRACE_PKINIT_NO_CA_ANCHOR(context, filename); + if (id_cryptoctx->trustedCAs == NULL) + sk_X509_free(ca_certs); + } else { +@@ -5530,7 +5518,7 @@ load_cas_and_crls(krb5_context context, + break; + case CATYPE_INTERMEDIATES: + if (sk_X509_num(ca_certs) == 0) { +- pkiDebug("no intermediates in file, %s\n", filename); ++ TRACE_PKINIT_NO_CA_INTERMEDIATE(context, filename); + if (id_cryptoctx->intermediateCAs == NULL) + sk_X509_free(ca_certs); + } else { +@@ -5540,7 +5528,7 @@ load_cas_and_crls(krb5_context context, + break; + case CATYPE_CRLS: + if (sk_X509_CRL_num(ca_crls) == 0) { +- pkiDebug("no crls in file, %s\n", filename); ++ TRACE_PKINIT_NO_CRL(context, filename); + if (id_cryptoctx->revoked == NULL) + sk_X509_CRL_free(ca_crls); + } else { +@@ -5626,14 +5614,14 @@ crypto_load_cas_and_crls(krb5_context context, + int catype, + char *id) + { +- pkiDebug("%s: called with idtype %s and catype %s\n", +- __FUNCTION__, idtype2string(idtype), catype2string(catype)); + switch (idtype) { + case IDTYPE_FILE: ++ TRACE_PKINIT_LOAD_FROM_FILE(context); + return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx, + id_cryptoctx, catype, id); + break; + case IDTYPE_DIR: ++ TRACE_PKINIT_LOAD_FROM_DIR(context); + return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx, + id_cryptoctx, catype, id); + break; +diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c +index a897efa25..737552e85 100644 +--- a/src/plugins/preauth/pkinit/pkinit_identity.c ++++ b/src/plugins/preauth/pkinit/pkinit_identity.c +@@ -608,7 +608,6 @@ pkinit_identity_prompt(krb5_context context, + retval = pkinit_cert_matching(context, plg_cryptoctx, + req_cryptoctx, id_cryptoctx, princ); + if (retval) { +- pkiDebug("%s: No matching certificate found\n", __FUNCTION__); + crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx, + id_cryptoctx); + goto errout; +@@ -621,8 +620,6 @@ pkinit_identity_prompt(krb5_context context, + retval = crypto_cert_select_default(context, plg_cryptoctx, + req_cryptoctx, id_cryptoctx); + if (retval) { +- pkiDebug("%s: Failed while selecting default certificate\n", +- __FUNCTION__); + crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx, + id_cryptoctx); + goto errout; +diff --git a/src/plugins/preauth/pkinit/pkinit_matching.c b/src/plugins/preauth/pkinit/pkinit_matching.c +index a50c50c8d..cad4c2b9a 100644 +--- a/src/plugins/preauth/pkinit/pkinit_matching.c ++++ b/src/plugins/preauth/pkinit/pkinit_matching.c +@@ -812,6 +812,7 @@ pkinit_cert_matching(krb5_context context, + goto cleanup; + } + } else { ++ TRACE_PKINIT_NO_MATCHING_CERT(context); + retval = ENOENT; /* XXX */ + goto cleanup; + } +diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c +index 32ca122f2..9c6e96c9e 100644 +--- a/src/plugins/preauth/pkinit/pkinit_srv.c ++++ b/src/plugins/preauth/pkinit/pkinit_srv.c +@@ -188,6 +188,7 @@ verify_client_san(krb5_context context, + plgctx->opts->allow_upn ? &upns : NULL, + NULL); + if (retval == ENOENT) { ++ TRACE_PKINIT_SERVER_NO_SAN(context); + goto out; + } else if (retval) { + pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__); +@@ -224,7 +225,7 @@ verify_client_san(krb5_context context, + krb5_free_unparsed_name(context, san_string); + #endif + if (cb->match_client(context, rock, princs[i])) { +- pkiDebug("%s: pkinit san match found\n", __FUNCTION__); ++ TRACE_PKINIT_SERVER_MATCHING_SAN_FOUND(context); + *valid_san = 1; + retval = 0; + goto out; +@@ -252,7 +253,7 @@ verify_client_san(krb5_context context, + krb5_free_unparsed_name(context, san_string); + #endif + if (cb->match_client(context, rock, upns[i])) { +- pkiDebug("%s: upn san match found\n", __FUNCTION__); ++ TRACE_PKINIT_SERVER_MATCHING_UPN_FOUND(context); + *valid_san = 1; + retval = 0; + goto out; +@@ -300,7 +301,7 @@ verify_client_eku(krb5_context context, + *eku_accepted = 0; + + if (plgctx->opts->require_eku == 0) { +- pkiDebug("%s: configuration requests no EKU checking\n", __FUNCTION__); ++ TRACE_PKINIT_SERVER_EKU_SKIP(context); + *eku_accepted = 1; + retval = 0; + goto out; +@@ -364,6 +365,7 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules, + ret = KRB5_PLUGIN_NO_HANDLE; + for (i = 0; certauth_modules != NULL && certauth_modules[i] != NULL; i++) { + h = certauth_modules[i]; ++ TRACE_PKINIT_SERVER_CERT_AUTH(context, h->vt.name); + ret = h->vt.authorize(context, h->moddata, cert, cert_len, client, + &opts, db_ent, &ais); + if (ret == 0) +@@ -449,7 +451,7 @@ pkinit_server_verify_padata(krb5_context context, + + switch ((int)data->pa_type) { + case KRB5_PADATA_PK_AS_REQ: +- pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n"); ++ TRACE_PKINIT_SERVER_PADATA_VERIFY(context); + retval = k5int_decode_krb5_pa_pk_as_req(&k5data, &reqp); + if (retval) { + pkiDebug("decode_krb5_pa_pk_as_req failed\n"); +@@ -472,7 +474,7 @@ pkinit_server_verify_padata(krb5_context context, + break; + case KRB5_PADATA_PK_AS_REP_OLD: + case KRB5_PADATA_PK_AS_REQ_OLD: +- pkiDebug("processing KRB5_PADATA_PK_AS_REQ_OLD\n"); ++ TRACE_PKINIT_SERVER_PADATA_VERIFY_OLD(context); + retval = k5int_decode_krb5_pa_pk_as_req_draft9(&k5data, &reqp9); + if (retval) { + pkiDebug("decode_krb5_pa_pk_as_req_draft9 failed\n"); +@@ -500,7 +502,7 @@ pkinit_server_verify_padata(krb5_context context, + goto cleanup; + } + if (retval) { +- pkiDebug("pkcs7_signeddata_verify failed\n"); ++ TRACE_PKINIT_SERVER_PADATA_VERIFY_FAIL(context); + goto cleanup; + } + if (is_signed) { +@@ -830,7 +832,7 @@ pkinit_server_return_padata(krb5_context context, + return ENOENT; + } + +- pkiDebug("pkinit_return_padata: entered!\n"); ++ TRACE_PKINIT_SERVER_RETURN_PADATA(context); + reqctx = (pkinit_kdc_req_context)modreq; + + if (encrypting_key->contents) { +@@ -1463,8 +1465,7 @@ pkinit_san_authorize(krb5_context context, krb5_certauth_moddata moddata, + return ret; + + if (!valid_san) { +- pkiDebug("%s: did not find an acceptable SAN in user certificate\n", +- __FUNCTION__); ++ TRACE_PKINIT_SERVER_SAN_REJECT(context); + return KRB5KDC_ERR_CLIENT_NAME_MISMATCH; + } + +@@ -1490,8 +1491,7 @@ pkinit_eku_authorize(krb5_context context, krb5_certauth_moddata moddata, + return ret; + + if (!valid_eku) { +- pkiDebug("%s: did not find an acceptable EKU in user certificate\n", +- __FUNCTION__); ++ TRACE_PKINIT_SERVER_EKU_REJECT(context); + return KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE; + } + +@@ -1617,7 +1617,7 @@ pkinit_server_plugin_init(krb5_context context, + return ENOMEM; + + for (i = 0, j = 0; i < numrealms; i++) { +- pkiDebug("%s: processing realm '%s'\n", __FUNCTION__, realmnames[i]); ++ TRACE_PKINIT_SERVER_INIT_REALM(context, realmnames[i]); + retval = pkinit_server_plugin_init_realm(context, realmnames[i], &plgctx); + if (retval == 0 && plgctx != NULL) + realm_contexts[j++] = plgctx; +diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h +index 458d0961e..6abe28c0c 100644 +--- a/src/plugins/preauth/pkinit/pkinit_trace.h ++++ b/src/plugins/preauth/pkinit/pkinit_trace.h +@@ -52,7 +52,7 @@ + #define TRACE_PKINIT_CLIENT_REP_CHECKSUM_FAIL(c, expected, received) \ + TRACE(c, "PKINIT client checksum mismatch: expected {cksum}, " \ + "received {cksum}", expected, received) +-#define TRACE_PKINIT_CLIENT_REP_DH(c) \ ++#define TRACE_PKINIT_CLIENT_REP_DH(c) \ + TRACE(c, "PKINIT client verified DH reply") + #define TRACE_PKINIT_CLIENT_REP_DH_FAIL(c) \ + TRACE(c, "PKINIT client could not verify DH reply") +@@ -91,6 +91,72 @@ + #define TRACE_PKINIT_OPENSSL_ERROR(c, msg) \ + TRACE(c, "PKINIT OpenSSL error: {str}", msg) + ++#define TRACE_PKINIT_SERVER_CERT_AUTH(c, modname) \ ++ TRACE(c, "PKINIT server authorizing cert with module {str}", \ ++ modname) ++#define TRACE_PKINIT_SERVER_EKU_REJECT(c) \ ++ TRACE(c, "PKINIT server found no acceptable EKU in client cert") ++#define TRACE_PKINIT_SERVER_EKU_SKIP(c) \ ++ TRACE(c, "PKINIT server skipping EKU check due to configuration") ++#define TRACE_PKINIT_SERVER_INIT_REALM(c, realm) \ ++ TRACE(c, "PKINIT server initializing realm {str}", realm) ++#define TRACE_PKINIT_SERVER_MATCHING_UPN_FOUND(c) \ ++ TRACE(c, "PKINIT server found a matching UPN SAN in client cert") ++#define TRACE_PKINIT_SERVER_MATCHING_SAN_FOUND(c) \ ++ TRACE(c, "PKINIT server found a matching SAN in client cert") ++#define TRACE_PKINIT_SERVER_NO_SAN(c) \ ++ TRACE(c, "PKINIT server found no SAN in client cert") ++#define TRACE_PKINIT_SERVER_PADATA_VERIFY(c) \ ++ TRACE(c, "PKINIT server verifying KRB5_PADATA_PK_AS_REQ") ++#define TRACE_PKINIT_SERVER_PADATA_VERIFY_OLD(c) \ ++ TRACE(c, "PKINIT server verifying KRB5_PADATA_PK_AS_REQ_OLD") ++#define TRACE_PKINIT_SERVER_PADATA_VERIFY_FAIL(c) \ ++ TRACE(c, "PKINIT server failed to verify PA data") ++#define TRACE_PKINIT_SERVER_RETURN_PADATA(c) \ ++ TRACE(c, "PKINIT server returning PA data") ++#define TRACE_PKINIT_SERVER_SAN_REJECT(c) \ ++ TRACE(c, "PKINIT server found no acceptable SAN in client cert") ++ ++#define TRACE_PKINIT_EKU(c) \ ++ TRACE(c, "PKINIT found acceptable EKU and digitalSignature KU") ++#define TRACE_PKINIT_EKU_NO_KU(c) \ ++ TRACE(c, "PKINIT found acceptable EKU but no digitalSignature KU") ++#define TRACE_PKINIT_LOADED_CERT(c, name) \ ++ TRACE(c, "PKINIT loaded cert and key for {str}", name) ++#define TRACE_PKINIT_LOAD_FROM_FILE(c) \ ++ TRACE(c, "PKINIT loading CA certs and CRLs from FILE") ++#define TRACE_PKINIT_LOAD_FROM_DIR(c) \ ++ TRACE(c, "PKINIT loading CA certs and CRLs from DIR") ++#define TRACE_PKINIT_NO_CA_ANCHOR(c, file) \ ++ TRACE(c, "PKINIT no anchor CA in file {str}", file) ++#define TRACE_PKINIT_NO_CA_INTERMEDIATE(c, file) \ ++ TRACE(c, "PKINIT no intermediate CA in file {str}", file) ++#define TRACE_PKINIT_NO_CERT(c) \ ++ TRACE(c, "PKINIT no certificate provided") ++#define TRACE_PKINIT_NO_CERT_AND_KEY(c, dirname) \ ++ TRACE(c, "PKINIT no cert and key pair found in directory {str}", \ ++ dirname) ++#define TRACE_PKINIT_NO_CRL(c, file) \ ++ TRACE(c, "PKINIT no CRL in file {str}", file) ++#define TRACE_PKINIT_NO_DEFAULT_CERT(c, count) \ ++ TRACE(c, "PKINIT error: There are {int} certs, but there must " \ ++ "be exactly one.", count) ++#define TRACE_PKINIT_NO_MATCHING_CERT(c) \ ++ TRACE(c, "PKINIT no matching certificate found") ++#define TRACE_PKINIT_NO_PRIVKEY(c) \ ++ TRACE(c, "PKINIT no private key provided") ++#define TRACE_PKINIT_PKCS_DECODE_FAIL(c, name) \ ++ TRACE(c, "PKINIT failed to decode PKCS12 file {str} contents", name) ++#define TRACE_PKINIT_PKCS_OPEN_FAIL(c, name, err) \ ++ TRACE(c, "PKINIT failed to open PKCS12 file {str}: err {errno}", \ ++ name, err) ++#define TRACE_PKINIT_PKCS_PARSE_FAIL_FIRST(c) \ ++ TRACE(c, "PKINIT initial PKCS12_parse with no password failed") ++#define TRACE_PKINIT_PKCS_PARSE_FAIL_SECOND(c) \ ++ TRACE(c, "PKINIT second PKCS12_parse with password failed") ++#define TRACE_PKINIT_PKCS_PROMPT_FAIL(c) \ ++ TRACE(c, "PKINIT failed to prompt for PKCS12 password") ++ + #define TRACE_CERTAUTH_VTINIT_FAIL(c, ret) \ + TRACE(c, "certauth module failed to init vtable: {kerr}", ret) + #define TRACE_CERTAUTH_INIT_FAIL(c, name, ret) \ diff --git a/SOURCES/Correct-error-handling-bug-in-prior-commit.patch b/SOURCES/Correct-error-handling-bug-in-prior-commit.patch index e080091..83da7f4 100644 --- a/SOURCES/Correct-error-handling-bug-in-prior-commit.patch +++ b/SOURCES/Correct-error-handling-bug-in-prior-commit.patch @@ -1,4 +1,4 @@ -From e9a48c7c89def99b0e60a8b83646a345966c077c Mon Sep 17 00:00:00 2001 +From ca3e61600f1400974c63b2abb30b44f0c94d550b Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Thu, 23 Mar 2017 13:42:55 -0400 Subject: [PATCH] Correct error handling bug in prior commit @@ -9,6 +9,7 @@ possibly-modified alias. ticket: 8561 (cherry picked from commit 7fdaef7c3280c86b5df25ae061fb04cc56d8620c) +Signed-off-by: Robbie Harwood --- src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SOURCES/Deindent-crypto_retrieve_X509_sans.patch b/SOURCES/Deindent-crypto_retrieve_X509_sans.patch index 330820d..3864cd3 100644 --- a/SOURCES/Deindent-crypto_retrieve_X509_sans.patch +++ b/SOURCES/Deindent-crypto_retrieve_X509_sans.patch @@ -9,6 +9,7 @@ return parameters are always initialized. (cherry picked from commit c6b772523db9d7791ee1c56eb512c4626556a4e7) (cherry picked from commit 23086ac768a32db1e40a9b63684dbcfd76aba033) +Signed-off-by: Robbie Harwood --- src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 224 +++++++++++---------- 1 file changed, 114 insertions(+), 110 deletions(-) diff --git a/SOURCES/Expose-context-errors-in-pkinit_server_plugin_init.patch b/SOURCES/Expose-context-errors-in-pkinit_server_plugin_init.patch new file mode 100644 index 0000000..3144401 --- /dev/null +++ b/SOURCES/Expose-context-errors-in-pkinit_server_plugin_init.patch @@ -0,0 +1,74 @@ +From 9c0a06f38189d255575acdae5efb22b76b4c33b3 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Mon, 13 Nov 2017 13:32:37 -0500 +Subject: [PATCH] Expose context errors in pkinit_server_plugin_init + +Commit 3ff426b9048a8024e5c175256c63cd0ad0572320 attempted to display +an error when OCSP support was requested, but this error message was +suppressed in pkinit_server_plugin_init(). Add a trace log for each +realm initialization error, and pass through the realm initialization +error when the KDC serves only one realm. Other error messages from +pkinit_init_kdc_profile(), such as missing pkinit_identity or +pkinit_anchors, are also now exposted. + +[ghudson@mit.edu: clarified commit message] + +ticket: 8621 (new) +target_version: 1.16 +tags: pullup + +(cherry picked from commit 225aab3540c13c6289b22022d5e110f6fc26151d) +Signed-off-by: Robbie Harwood +--- + src/plugins/preauth/pkinit/pkinit_srv.c | 19 +++++++++++++------ + src/plugins/preauth/pkinit/pkinit_trace.h | 3 +++ + 2 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c +index 8e77606f8..143d331a2 100644 +--- a/src/plugins/preauth/pkinit/pkinit_srv.c ++++ b/src/plugins/preauth/pkinit/pkinit_srv.c +@@ -1622,16 +1622,23 @@ pkinit_server_plugin_init(krb5_context context, + + for (i = 0, j = 0; i < numrealms; i++) { + TRACE_PKINIT_SERVER_INIT_REALM(context, realmnames[i]); +- retval = pkinit_server_plugin_init_realm(context, realmnames[i], &plgctx); +- if (retval == 0 && plgctx != NULL) ++ krb5_clear_error_message(context); ++ retval = pkinit_server_plugin_init_realm(context, realmnames[i], ++ &plgctx); ++ if (retval) ++ TRACE_PKINIT_SERVER_INIT_FAIL(context, realmnames[i], retval); ++ else + realm_contexts[j++] = plgctx; + } + + if (j == 0) { +- retval = EINVAL; +- krb5_set_error_message(context, retval, +- _("No realms configured correctly for pkinit " +- "support")); ++ if (numrealms == 1) { ++ k5_prependmsg(context, retval, "PKINIT initialization failed"); ++ } else { ++ retval = EINVAL; ++ k5_setmsg(context, retval, ++ _("No realms configured correctly for pkinit support")); ++ } + goto errout; + } + +diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h +index 6abe28c0c..8d489469f 100644 +--- a/src/plugins/preauth/pkinit/pkinit_trace.h ++++ b/src/plugins/preauth/pkinit/pkinit_trace.h +@@ -100,6 +100,9 @@ + TRACE(c, "PKINIT server skipping EKU check due to configuration") + #define TRACE_PKINIT_SERVER_INIT_REALM(c, realm) \ + TRACE(c, "PKINIT server initializing realm {str}", realm) ++#define TRACE_PKINIT_SERVER_INIT_FAIL(c, realm, retval) \ ++ TRACE(c, "PKINIT server initialization failed for realm {str}: {kerr}", \ ++ realm, retval) + #define TRACE_PKINIT_SERVER_MATCHING_UPN_FOUND(c) \ + TRACE(c, "PKINIT server found a matching UPN SAN in client cert") + #define TRACE_PKINIT_SERVER_MATCHING_SAN_FOUND(c) \ diff --git a/SOURCES/Fix-bugs-in-kdcpolicy-commit.patch b/SOURCES/Fix-bugs-in-kdcpolicy-commit.patch new file mode 100644 index 0000000..533818c --- /dev/null +++ b/SOURCES/Fix-bugs-in-kdcpolicy-commit.patch @@ -0,0 +1,131 @@ +From d59b00fd1fdcc473739f3033c0f67eb402f20d9c Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Sat, 19 Aug 2017 19:09:24 -0400 +Subject: [PATCH] Fix bugs in kdcpolicy commit + +Commit d0969f6a8170344031ef58fd2a161190f1edfb96 added tests using +"klist ccachname -e", which does not work with a POSIX-conformant +getopt() implementation such as the one in Solaris. Fix +t_kdcpolicy.py to use "klist -e ccachename" instead. + +The tests could fail if the clock second rolled over between kinit and +kvno. Divide service ticket maximum lifetimes by 2 in the test module +to correctly exercise TGS policy restrictions and ensure that service +tickets are not constrained by the TGT end time. + +Also use the correct trace macro when a kdcpolicy module declines to +initialize (my mistake when revising the commit, noted by rharwood). + +ticket: 8606 +(cherry picked from commit 09acbd91efc6df54e1572285ffc94c6acb3a9113) +Signed-off-by: Robbie Harwood +--- + src/kdc/policy.c | 2 +- + src/plugins/kdcpolicy/test/main.c | 10 +++++----- + src/tests/t_kdcpolicy.py | 13 +++++++++---- + 3 files changed, 15 insertions(+), 10 deletions(-) + +diff --git a/src/kdc/policy.c b/src/kdc/policy.c +index e49644e06..26c16f97c 100644 +--- a/src/kdc/policy.c ++++ b/src/kdc/policy.c +@@ -222,7 +222,7 @@ load_kdcpolicy_plugins(krb5_context context) + if (h->vt.init != NULL) { + ret = h->vt.init(context, &h->moddata); + if (ret == KRB5_PLUGIN_NO_HANDLE) { +- TRACE_KADM5_AUTH_INIT_SKIP(context, h->vt.name); ++ TRACE_KDCPOLICY_INIT_SKIP(context, h->vt.name); + free(h); + continue; + } +diff --git a/src/plugins/kdcpolicy/test/main.c b/src/plugins/kdcpolicy/test/main.c +index eb8fde053..86c808958 100644 +--- a/src/plugins/kdcpolicy/test/main.c ++++ b/src/plugins/kdcpolicy/test/main.c +@@ -35,7 +35,7 @@ + #include + + static krb5_error_code +-output_from_indicator(const char *const *auth_indicators, ++output_from_indicator(const char *const *auth_indicators, int divisor, + krb5_deltat *lifetime_out, + krb5_deltat *renew_lifetime_out, + const char **status) +@@ -46,11 +46,11 @@ output_from_indicator(const char *const *auth_indicators, + } + + if (strcmp(auth_indicators[0], "ONE_HOUR") == 0) { +- *lifetime_out = 3600; ++ *lifetime_out = 3600 / divisor; + *renew_lifetime_out = *lifetime_out * 2; + return 0; + } else if (strcmp(auth_indicators[0], "SEVEN_HOURS") == 0) { +- *lifetime_out = 7 * 3600; ++ *lifetime_out = 7 * 3600 / divisor; + *renew_lifetime_out = *lifetime_out * 2; + return 0; + } +@@ -71,7 +71,7 @@ test_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata, + *status = "LOCAL_POLICY"; + return KRB5KDC_ERR_POLICY; + } +- return output_from_indicator(auth_indicators, lifetime_out, ++ return output_from_indicator(auth_indicators, 1, lifetime_out, + renew_lifetime_out, status); + } + +@@ -87,7 +87,7 @@ test_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata, + *status = "LOCAL_POLICY"; + return KRB5KDC_ERR_POLICY; + } +- return output_from_indicator(auth_indicators, lifetime_out, ++ return output_from_indicator(auth_indicators, 2, lifetime_out, + renew_lifetime_out, status); + } + +diff --git a/src/tests/t_kdcpolicy.py b/src/tests/t_kdcpolicy.py +index 6a745b959..b5d308461 100644 +--- a/src/tests/t_kdcpolicy.py ++++ b/src/tests/t_kdcpolicy.py +@@ -18,16 +18,21 @@ realm.run([kadminl, 'addprinc', '-pw', password('fail'), 'fail']) + def verify_time(out, target_time): + times = re.findall(r'\d\d/\d\d/\d\d \d\d:\d\d:\d\d', out) + times = [datetime.strptime(t, '%m/%d/%y %H:%M:%S') for t in times] ++ divisor = 1 + while len(times) > 0: + starttime = times.pop(0) + endtime = times.pop(0) + renewtime = times.pop(0) + +- if str(endtime - starttime) != target_time: ++ if str((endtime - starttime) * divisor) != target_time: + fail('unexpected lifetime value') +- if str(renewtime - endtime) != target_time: ++ if str((renewtime - endtime) * divisor) != target_time: + fail('unexpected renewable value') + ++ # Service tickets should have half the lifetime of initial ++ # tickets. ++ divisor = 2 ++ + rflags = ['-r', '1d', '-l', '12h'] + + # Test AS+TGS success path. +@@ -35,7 +40,7 @@ realm.kinit(realm.user_princ, password('user'), + rflags + ['-X', 'indicators=SEVEN_HOURS']) + realm.run([kvno, realm.host_princ]) + realm.run(['./adata', realm.host_princ], expected_msg='+97: [SEVEN_HOURS]') +-out = realm.run([klist, realm.ccache, '-e']) ++out = realm.run([klist, '-e', realm.ccache]) + verify_time(out, '7:00:00') + + # Test AS+TGS success path with different values. +@@ -43,7 +48,7 @@ realm.kinit(realm.user_princ, password('user'), + rflags + ['-X', 'indicators=ONE_HOUR']) + realm.run([kvno, realm.host_princ]) + realm.run(['./adata', realm.host_princ], expected_msg='+97: [ONE_HOUR]') +-out = realm.run([klist, realm.ccache, '-e']) ++out = realm.run([klist, '-e', realm.ccache]) + verify_time(out, '1:00:00') + + # Test TGS failure path (using previous creds). diff --git a/SOURCES/Fix-certauth-built-in-module-returns.patch b/SOURCES/Fix-certauth-built-in-module-returns.patch new file mode 100644 index 0000000..f512f49 --- /dev/null +++ b/SOURCES/Fix-certauth-built-in-module-returns.patch @@ -0,0 +1,125 @@ +From 41b9111b48e53bf7864ed1f134e0433b070fa900 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Thu, 24 Aug 2017 11:11:46 -0400 +Subject: [PATCH] Fix certauth built-in module returns + +The PKINIT certauth eku module should never authoritatively authorize +a certificate, because an extended key usage does not establish a +relationship between the certificate and any specific user; it only +establishes that the certificate was created for PKINIT client +authentication. Therefore, pkinit_eku_authorize() should return +KRB5_PLUGIN_NO_HANDLE on success, not 0. + +The certauth san module should pass if it does not find any SANs of +the types it can match against; the presence of other types of SANs +should not cause it to explicitly deny a certificate. Check for an +empty result from crypto_retrieve_cert_sans() in verify_client_san(), +instead of returning ENOENT from crypto_retrieve_cert_sans() when +there are no SANs at all. + +ticket: 8561 +(cherry picked from commit 07243f85a760fb37f0622d7ff0177db3f19ab025) +Signed-off-by: Robbie Harwood +--- + src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 39 ++++++++++------------ + src/plugins/preauth/pkinit/pkinit_srv.c | 14 +++++--- + 2 files changed, 27 insertions(+), 26 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index 70e230ec2..7fa2efd21 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -2137,7 +2137,6 @@ crypto_retrieve_X509_sans(krb5_context context, + + if (!(ext = X509_get_ext(cert, l)) || !(ialt = X509V3_EXT_d2i(ext))) { + pkiDebug("%s: found no subject alt name extensions\n", __FUNCTION__); +- retval = ENOENT; + goto cleanup; + } + num_sans = sk_GENERAL_NAME_num(ialt); +@@ -2240,31 +2239,29 @@ crypto_retrieve_X509_sans(krb5_context context, + sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free); + + retval = 0; +- if (princs) ++ if (princs != NULL && *princs != NULL) { + *princs_ret = princs; +- if (upns) ++ princs = NULL; ++ } ++ if (upns != NULL && *upns != NULL) { + *upn_ret = upns; +- if (dnss) ++ upns = NULL; ++ } ++ if (dnss != NULL && *dnss != NULL) { + *dns_ret = dnss; ++ dnss = NULL; ++ } + + cleanup: +- if (retval) { +- if (princs != NULL) { +- for (i = 0; princs[i] != NULL; i++) +- krb5_free_principal(context, princs[i]); +- free(princs); +- } +- if (upns != NULL) { +- for (i = 0; upns[i] != NULL; i++) +- krb5_free_principal(context, upns[i]); +- free(upns); +- } +- if (dnss != NULL) { +- for (i = 0; dnss[i] != NULL; i++) +- free(dnss[i]); +- free(dnss); +- } +- } ++ for (i = 0; princs != NULL && princs[i] != NULL; i++) ++ krb5_free_principal(context, princs[i]); ++ free(princs); ++ for (i = 0; upns != NULL && upns[i] != NULL; i++) ++ krb5_free_principal(context, upns[i]); ++ free(upns); ++ for (i = 0; dnss != NULL && dnss[i] != NULL; i++) ++ free(dnss[i]); ++ free(dnss); + return retval; + } + +diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c +index 9c6e96c9e..8e77606f8 100644 +--- a/src/plugins/preauth/pkinit/pkinit_srv.c ++++ b/src/plugins/preauth/pkinit/pkinit_srv.c +@@ -187,14 +187,18 @@ verify_client_san(krb5_context context, + &princs, + plgctx->opts->allow_upn ? &upns : NULL, + NULL); +- if (retval == ENOENT) { +- TRACE_PKINIT_SERVER_NO_SAN(context); +- goto out; +- } else if (retval) { ++ if (retval) { + pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__); + retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH; + goto out; + } ++ ++ if (princs == NULL && upns == NULL) { ++ TRACE_PKINIT_SERVER_NO_SAN(context); ++ retval = ENOENT; ++ goto out; ++ } ++ + /* XXX Verify this is consistent with client side XXX */ + #if 0 + retval = call_san_checking_plugins(context, plgctx, reqctx, princs, +@@ -1495,7 +1499,7 @@ pkinit_eku_authorize(krb5_context context, krb5_certauth_moddata moddata, + return KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE; + } + +- return 0; ++ return KRB5_PLUGIN_NO_HANDLE; + } + + static krb5_error_code diff --git a/SOURCES/Fix-in_clock_skew-and-use-it-in-AS-client-code.patch b/SOURCES/Fix-in_clock_skew-and-use-it-in-AS-client-code.patch new file mode 100644 index 0000000..fb84846 --- /dev/null +++ b/SOURCES/Fix-in_clock_skew-and-use-it-in-AS-client-code.patch @@ -0,0 +1,59 @@ +From 7e914206a676fb8f972c8021e97fab86a155488b Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Mon, 24 Apr 2017 02:02:36 -0400 +Subject: [PATCH] Fix in_clock_skew() and use it in AS client code + +Add a context parameter to the in_clock_skew() macro so that it isn't +implicitly relying on a local variable. Use it in +get_in_tkt.c:verify_as_reply(). + +(cherry picked from commit 28a07a6461bb443b7fa75cc5cb859ad0db4cbb5a) +Signed-off-by: Robbie Harwood +--- + src/lib/krb5/krb/gc_via_tkt.c | 2 +- + src/lib/krb5/krb/get_in_tkt.c | 4 ++-- + src/lib/krb5/krb/int-proto.h | 3 ++- + 3 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c +index 4c0a1a461..c85d8b8d8 100644 +--- a/src/lib/krb5/krb/gc_via_tkt.c ++++ b/src/lib/krb5/krb/gc_via_tkt.c +@@ -305,7 +305,7 @@ krb5int_process_tgs_reply(krb5_context context, + goto cleanup; + + if (!in_cred->times.starttime && +- !in_clock_skew(dec_rep->enc_part2->times.starttime, ++ !in_clock_skew(context, dec_rep->enc_part2->times.starttime, + timestamp)) { + retval = KRB5_KDCREP_SKEW; + goto cleanup; +diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c +index 54badbbc3..a058f5bd7 100644 +--- a/src/lib/krb5/krb/get_in_tkt.c ++++ b/src/lib/krb5/krb/get_in_tkt.c +@@ -287,8 +287,8 @@ verify_as_reply(krb5_context context, + return retval; + } else { + if ((request->from == 0) && +- (labs(as_reply->enc_part2->times.starttime - time_now) +- > context->clockskew)) ++ !in_clock_skew(context, as_reply->enc_part2->times.starttime, ++ time_now)) + return (KRB5_KDCREP_SKEW); + } + return 0; +diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h +index 6da74858e..44eca359f 100644 +--- a/src/lib/krb5/krb/int-proto.h ++++ b/src/lib/krb5/krb/int-proto.h +@@ -83,7 +83,8 @@ krb5int_construct_matching_creds(krb5_context context, krb5_flags options, + krb5_creds *in_creds, krb5_creds *mcreds, + krb5_flags *fields); + +-#define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew) ++#define in_clock_skew(context, date, now) \ ++ (labs((date) - (now)) < (context)->clockskew) + + #define IS_TGS_PRINC(p) ((p)->length == 2 && \ + data_eq_string((p)->data[0], KRB5_TGS_NAME)) diff --git a/SOURCES/Fix-make-certs.sh-for-OpenSSL-1.1.patch b/SOURCES/Fix-make-certs.sh-for-OpenSSL-1.1.patch new file mode 100644 index 0000000..f02f9c5 --- /dev/null +++ b/SOURCES/Fix-make-certs.sh-for-OpenSSL-1.1.patch @@ -0,0 +1,71 @@ +From 7221a9f695016d3e4873bb799f06665ec74387f8 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Wed, 6 Sep 2017 12:56:37 -0400 +Subject: [PATCH] Fix make-certs.sh for OpenSSL 1.1 + +The openssl req commands in make-certs.sh contain -subj options which +were ignored in favor of the config file prior to OpenSSL 1.1. When +they are used, they remove elements of the subject which are now +required by t_pkinit.py. + +(cherry picked from commit b0473da67d72e43b9f03b703869069348e872efc) +[rharwood@redhat.com: remove newer sections in make-certs.sh] +Signed-off-by: Robbie Harwood +--- + src/tests/dejagnu/pkinit-certs/make-certs.sh | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/src/tests/dejagnu/pkinit-certs/make-certs.sh b/src/tests/dejagnu/pkinit-certs/make-certs.sh +index 0f07709b0..0d8c2019a 100755 +--- a/src/tests/dejagnu/pkinit-certs/make-certs.sh ++++ b/src/tests/dejagnu/pkinit-certs/make-certs.sh +@@ -122,15 +122,14 @@ SUBJECT=ca openssl req -config openssl.cnf -new -x509 -extensions exts_ca \ + -set_serial 1 -days $DAYS -key privkey.pem -out ca.pem + + # Generate a KDC certificate. +-SUBJECT=kdc openssl req -config openssl.cnf -new -subj /CN=kdc \ +- -key privkey.pem -out kdc.csr ++SUBJECT=kdc openssl req -config openssl.cnf -new -key privkey.pem -out kdc.csr + SUBJECT=kdc openssl x509 -extfile openssl.cnf -extensions exts_kdc \ + -set_serial 2 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ + -out kdc.pem -in kdc.csr + + # Generate a client certificate and PKCS#12 bundles. +-SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ +- -key privkey.pem -out user.csr ++SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \ ++ -out user.csr + SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_client \ + -set_serial 3 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ + -out user.pem -in user.csr +@@ -140,24 +139,24 @@ openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user-enc.p12 \ + -passout pass:encrypted + + # Generate a client certificate and PKCS#12 bundles with a UPN SAN. +-SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ +- -key privkey.pem -out user-upn.csr ++SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \ ++ -out user-upn.csr + SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn_client \ + -set_serial 4 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ + -out user-upn.pem -in user-upn.csr + openssl pkcs12 -export -in user-upn.pem -inkey privkey.pem -out user-upn.p12 \ + -passout pass: + +-SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ +- -key privkey.pem -out user-upn2.csr ++SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \ ++ -out user-upn2.csr + SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn2_client \ + -set_serial 5 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ + -out user-upn2.pem -in user-upn2.csr + openssl pkcs12 -export -in user-upn2.pem -inkey privkey.pem \ + -out user-upn2.p12 -passout pass: + +-SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ +- -key privkey.pem -out user-upn3.csr ++SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \ ++ -out user-upn3.csr + SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn3_client \ + -set_serial 6 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ + -out user-upn3.pem -in user-upn3.csr diff --git a/SOURCES/Fix-more-time-manipulations-for-y2038.patch b/SOURCES/Fix-more-time-manipulations-for-y2038.patch new file mode 100644 index 0000000..44252dc --- /dev/null +++ b/SOURCES/Fix-more-time-manipulations-for-y2038.patch @@ -0,0 +1,84 @@ +From 006c68f6ed266d5ea7a24512349a931f45160cc6 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Wed, 17 May 2017 14:52:09 -0400 +Subject: [PATCH] Fix more time manipulations for y2038 + +Use timestamp helper functions to ensure that more operations are safe +after y2038, and display the current timestamp as unsigned in +krb5int_trace(). + +ticket: 8352 +(cherry picked from commit a60db180211a383bd382afe729e9309acb8dcf53) +Signed-off-by: Robbie Harwood +--- + src/kadmin/server/misc.c | 2 +- + src/kdc/dispatch.c | 2 +- + src/lib/krb5/os/c_ustime.c | 8 ++++---- + src/lib/krb5/os/trace.c | 2 +- + 4 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c +index 27a6376af..a75b65a26 100644 +--- a/src/kadmin/server/misc.c ++++ b/src/kadmin/server/misc.c +@@ -184,7 +184,7 @@ check_min_life(void *server_handle, krb5_principal principal, + (void) kadm5_free_principal_ent(handle->lhandle, &princ); + return (ret == KADM5_UNK_POLICY) ? 0 : ret; + } +- if((now - princ.last_pwd_change) < pol.pw_min_life && ++ if(ts_delta(now, princ.last_pwd_change) < pol.pw_min_life && + !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { + if (msg_ret != NULL) { + time_t until; +diff --git a/src/kdc/dispatch.c b/src/kdc/dispatch.c +index 3a169ebc7..16a35d2be 100644 +--- a/src/kdc/dispatch.c ++++ b/src/kdc/dispatch.c +@@ -104,7 +104,7 @@ reseed_random(krb5_context kdc_err_context) + if (last_os_random == 0) + last_os_random = now; + /* Grab random data from OS every hour*/ +- if (now-last_os_random >= 60 * 60) { ++ if (ts_delta(now, last_os_random) >= 60 * 60) { + krb5_c_random_os_entropy(kdc_err_context, 0, NULL); + last_os_random = now; + } +diff --git a/src/lib/krb5/os/c_ustime.c b/src/lib/krb5/os/c_ustime.c +index 871d72183..68fb381f4 100644 +--- a/src/lib/krb5/os/c_ustime.c ++++ b/src/lib/krb5/os/c_ustime.c +@@ -102,17 +102,17 @@ krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds) + putting now.sec in the past. But don't just use '<' because we + need to properly handle the case where the administrator intentionally + adjusted time backwards. */ +- if ((now.sec == last_time.sec-1) || +- ((now.sec == last_time.sec) && (now.usec <= last_time.usec))) { ++ if (now.sec == ts_incr(last_time.sec, -1) || ++ (now.sec == last_time.sec && !ts_after(last_time.usec, now.usec))) { + /* Correct 'now' to be exactly one microsecond later than 'last_time'. + Note that _because_ we perform this hack, 'now' may be _earlier_ + than 'last_time', even though the system time is monotonically + increasing. */ + + now.sec = last_time.sec; +- now.usec = ++last_time.usec; ++ now.usec = ts_incr(last_time.usec, 1); + if (now.usec >= 1000000) { +- ++now.sec; ++ now.sec = ts_incr(now.sec, 1); + now.usec = 0; + } + } +diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c +index a19246128..74c315c90 100644 +--- a/src/lib/krb5/os/trace.c ++++ b/src/lib/krb5/os/trace.c +@@ -350,7 +350,7 @@ krb5int_trace(krb5_context context, const char *fmt, ...) + goto cleanup; + if (krb5_crypto_us_timeofday(&sec, &usec) != 0) + goto cleanup; +- if (asprintf(&msg, "[%d] %d.%d: %s\n", (int) getpid(), (int) sec, ++ if (asprintf(&msg, "[%d] %u.%d: %s\n", (int) getpid(), (unsigned int) sec, + (int) usec, str) < 0) + goto cleanup; + info.message = msg; diff --git a/SOURCES/Improve-PKINIT-UPN-SAN-matching.patch b/SOURCES/Improve-PKINIT-UPN-SAN-matching.patch index d4d45c6..aaf15b6 100644 --- a/SOURCES/Improve-PKINIT-UPN-SAN-matching.patch +++ b/SOURCES/Improve-PKINIT-UPN-SAN-matching.patch @@ -14,6 +14,7 @@ parse UPN values as enterprise principals. ticket: 8528 (new) (cherry picked from commit 46ff765e1fb8cbec2bb602b43311269e695dbedc) +Signed-off-by: Robbie Harwood --- src/include/krb5/kdcpreauth_plugin.h | 13 ++++++++++ src/kdc/kdc_preauth.c | 28 ++++++++++++++++++++-- diff --git a/SOURCES/Make-timestamp-manipulations-y2038-safe.patch b/SOURCES/Make-timestamp-manipulations-y2038-safe.patch new file mode 100644 index 0000000..8ae5272 --- /dev/null +++ b/SOURCES/Make-timestamp-manipulations-y2038-safe.patch @@ -0,0 +1,1845 @@ +From 7c671a869d1fc21b5154c035d568d5b5fd940783 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Sat, 22 Apr 2017 12:52:17 -0400 +Subject: [PATCH] Make timestamp manipulations y2038-safe + +Wherever we manipulate krb5_timestamp values using arithmetic, +comparison operations, or conversion to time_t, use the new helper +functions in k5-int.h to ensure that the operations work after y2038 +and do not exhibit undefined behavior. (Relying on +implementation-defined conversion to signed values is okay as we test +that in configure.in.) + +In printf format strings, use %u instead of signed types. When +exporting creds with k5_json_array_fmt(), use a long long so that +timestamps after y2038 aren't marshalled as negative numbers. When +parsing timestamps in test programs, use atoll() instead of atol() so +that positive timestamps after y2038 can be used as input. + +In ksu and klist, make printtime() take a krb5_timestamp parameter to +avoid an unnecessary conversion to time_t and back. + +As Leash does not use k5-int.h, use time_t values internally and +safely convert from libkrb5 timestamp values. + +ticket: 8352 +(cherry picked from commit a9cbbf0899f270fbb14f63ffbed1b6d542333641) +Signed-off-by: Robbie Harwood +--- + src/clients/kinit/kinit.c | 2 +- + src/clients/klist/klist.c | 20 ++++------- + src/clients/ksu/ccache.c | 20 +++-------- + src/clients/ksu/ksu.h | 2 +- + src/kadmin/cli/getdate.y | 2 +- + src/kadmin/cli/kadmin.c | 5 ++- + src/kadmin/dbutil/dump.c | 27 ++++++++------- + src/kadmin/dbutil/kdb5_mkey.c | 6 ++-- + src/kadmin/dbutil/tabdump.c | 2 +- + src/kadmin/testing/util/tcl_kadm5.c | 12 +++---- + src/kdc/do_as_req.c | 2 +- + src/kdc/do_tgs_req.c | 6 ++-- + src/kdc/extern.c | 4 ++- + src/kdc/fast_util.c | 4 +-- + src/kdc/kdc_log.c | 14 ++++---- + src/kdc/kdc_util.c | 20 +++++------ + src/kdc/kdc_util.h | 2 ++ + src/kdc/replay.c | 2 +- + src/kdc/tgs_policy.c | 7 ++-- + src/lib/gssapi/krb5/accept_sec_context.c | 8 +++-- + src/lib/gssapi/krb5/acquire_cred.c | 13 ++++--- + src/lib/gssapi/krb5/context_time.c | 2 +- + src/lib/gssapi/krb5/export_cred.c | 5 +-- + src/lib/gssapi/krb5/iakerb.c | 4 +-- + src/lib/gssapi/krb5/init_sec_context.c | 9 ++--- + src/lib/gssapi/krb5/inq_context.c | 2 +- + src/lib/gssapi/krb5/inq_cred.c | 5 +-- + src/lib/gssapi/krb5/s4u_gss_glue.c | 2 +- + src/lib/kadm5/chpass_util.c | 8 ++--- + src/lib/kadm5/srv/server_acl.c | 5 +-- + src/lib/kadm5/srv/svr_principal.c | 12 +++---- + src/lib/kdb/kdb5.c | 2 +- + src/lib/krb5/asn.1/asn1_k_encode.c | 3 +- + src/lib/krb5/ccache/cc_keyring.c | 14 ++++---- + src/lib/krb5/ccache/cc_memory.c | 4 +-- + src/lib/krb5/ccache/cc_retr.c | 4 +-- + src/lib/krb5/ccache/ccapi/stdcc_util.c | 40 +++++++++++----------- + src/lib/krb5/ccache/cccursor.c | 2 +- + src/lib/krb5/keytab/kt_file.c | 6 ++-- + src/lib/krb5/krb/gc_via_tkt.c | 7 ++-- + src/lib/krb5/krb/get_creds.c | 2 +- + src/lib/krb5/krb/get_in_tkt.c | 38 ++++++-------------- + src/lib/krb5/krb/gic_pwd.c | 4 +-- + src/lib/krb5/krb/int-proto.h | 2 +- + src/lib/krb5/krb/pac.c | 2 +- + src/lib/krb5/krb/str_conv.c | 4 +-- + src/lib/krb5/krb/t_kerb.c | 12 ++----- + src/lib/krb5/krb/valid_times.c | 4 +-- + src/lib/krb5/krb/vfy_increds.c | 2 +- + src/lib/krb5/os/timeofday.c | 2 +- + src/lib/krb5/os/toffset.c | 2 +- + src/lib/krb5/os/ustime.c | 6 ++-- + src/lib/krb5/rcache/rc_dfl.c | 3 +- + src/lib/krb5/rcache/t_replay.c | 8 ++--- + src/plugins/kdb/db2/lockout.c | 8 ++--- + src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c | 2 +- + src/plugins/kdb/ldap/libkdb_ldap/lockout.c | 8 ++--- + src/windows/cns/tktlist.c | 10 +++--- + src/windows/include/leashwin.h | 12 +++---- + src/windows/leash/KrbListTickets.cpp | 12 +++---- + src/windows/leash/LeashView.cpp | 22 ++++++------ + src/windows/leashdll/lshfunc.c | 2 +- + src/windows/ms2mit/ms2mit.c | 2 +- + 63 files changed, 230 insertions(+), 255 deletions(-) + +diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c +index f1cd1b73d..50065e32e 100644 +--- a/src/clients/kinit/kinit.c ++++ b/src/clients/kinit/kinit.c +@@ -318,7 +318,7 @@ parse_options(argc, argv, opts) + fprintf(stderr, _("Bad start time value %s\n"), optarg); + errflg++; + } else { +- opts->starttime = abs_starttime - time(0); ++ opts->starttime = ts_delta(abs_starttime, time(NULL)); + } + } + break; +diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c +index ba19788a2..ffeecc394 100644 +--- a/src/clients/klist/klist.c ++++ b/src/clients/klist/klist.c +@@ -72,7 +72,7 @@ void do_ccache_name (char *); + int show_ccache (krb5_ccache); + int check_ccache (krb5_ccache); + void do_keytab (char *); +-void printtime (time_t); ++void printtime (krb5_timestamp); + void one_addr (krb5_address *); + void fillit (FILE *, unsigned int, int); + +@@ -538,10 +538,10 @@ check_ccache(krb5_ccache cache) + while (!(ret = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) { + if (is_local_tgt(creds.server, &princ->realm)) { + found_tgt = TRUE; +- if (creds.times.endtime > now) ++ if (ts_after(creds.times.endtime, now)) + found_current_tgt = TRUE; + } else if (!krb5_is_config_principal(kcontext, creds.server) && +- creds.times.endtime > now) { ++ ts_after(creds.times.endtime, now)) { + found_current_cred = TRUE; + } + krb5_free_cred_contents(kcontext, &creds); +@@ -623,19 +623,13 @@ flags_string(cred) + } + + void +-printtime(tv) +- time_t tv; ++printtime(krb5_timestamp ts) + { +- char timestring[BUFSIZ]; +- char fill; ++ char timestring[BUFSIZ], fill = ' '; + +- fill = ' '; +- if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv, +- timestring, +- timestamp_width+1, +- &fill)) { ++ if (!krb5_timestamp_to_sfstring(ts, timestring, timestamp_width + 1, ++ &fill)) + printf("%s", timestring); +- } + } + + static void +diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c +index a0736f2da..236313b7b 100644 +--- a/src/clients/ksu/ccache.c ++++ b/src/clients/ksu/ccache.c +@@ -278,11 +278,11 @@ krb5_error_code krb5_check_exp(context, tkt_time) + context->clockskew); + + fprintf(stderr,"krb5_check_exp: currenttime - endtime %d \n", +- (currenttime - tkt_time.endtime )); ++ ts_delta(currenttime, tkt_time.endtime)); + + } + +- if (currenttime - tkt_time.endtime > context->clockskew){ ++ if (ts_delta(currenttime, tkt_time.endtime) > context->clockskew) { + retval = KRB5KRB_AP_ERR_TKT_EXPIRED ; + return retval; + } +@@ -323,21 +323,11 @@ char *flags_string(cred) + return(buf); + } + +-void printtime(tv) +- time_t tv; ++void printtime(krb5_timestamp ts) + { +- char fmtbuf[18]; +- char fill; +- krb5_timestamp tstamp; ++ char fmtbuf[18], fill = ' '; + +- /* XXXX ASSUMES sizeof(krb5_timestamp) >= sizeof(time_t) */ +- (void) localtime((time_t *)&tv); +- tstamp = tv; +- fill = ' '; +- if (!krb5_timestamp_to_sfstring(tstamp, +- fmtbuf, +- sizeof(fmtbuf), +- &fill)) ++ if (!krb5_timestamp_to_sfstring(ts, fmtbuf, sizeof(fmtbuf), &fill)) + printf("%s", fmtbuf); + } + +diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h +index ee8e9d6a0..3bf0bd438 100644 +--- a/src/clients/ksu/ksu.h ++++ b/src/clients/ksu/ksu.h +@@ -150,7 +150,7 @@ extern krb5_boolean krb5_find_princ_in_cred_list + extern krb5_error_code krb5_find_princ_in_cache + (krb5_context, krb5_ccache, krb5_principal, krb5_boolean *); + +-extern void printtime (time_t); ++extern void printtime (krb5_timestamp); + + /* authorization.c */ + extern krb5_boolean fowner (FILE *, uid_t); +diff --git a/src/kadmin/cli/getdate.y b/src/kadmin/cli/getdate.y +index 4f0c56f7e..0a19c5648 100644 +--- a/src/kadmin/cli/getdate.y ++++ b/src/kadmin/cli/getdate.y +@@ -118,7 +118,7 @@ static int getdate_yyerror (char *); + + + #define EPOCH 1970 +-#define EPOCH_END 2038 /* assumes 32 bits */ ++#define EPOCH_END 2106 /* assumes unsigned 32-bit range */ + #define HOUR(x) ((time_t)(x) * 60) + #define SECSPERDAY (24L * 60L * 60L) + +diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c +index c53c677a8..aee5c83b9 100644 +--- a/src/kadmin/cli/kadmin.c ++++ b/src/kadmin/cli/kadmin.c +@@ -31,8 +31,7 @@ + * library */ + + /* for "_" macro */ +-#include "k5-platform.h" +-#include ++#include "k5-int.h" + #include + #include + #include +@@ -144,8 +143,8 @@ strdate(krb5_timestamp when) + { + struct tm *tm; + static char out[40]; ++ time_t lcltim = ts2tt(when); + +- time_t lcltim = when; + tm = localtime(&lcltim); + strftime(out, sizeof(out), "%a %b %d %H:%M:%S %Z %Y", tm); + return out; +diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c +index cad53cfbf..a6fc4ea77 100644 +--- a/src/kadmin/dbutil/dump.c ++++ b/src/kadmin/dbutil/dump.c +@@ -379,11 +379,12 @@ k5beta7_common(krb5_context context, krb5_db_entry *entry, + fprintf(fp, "princ\t%d\t%lu\t%d\t%d\t%d\t%s\t", (int)entry->len, + (unsigned long)strlen(name), counter, (int)entry->n_key_data, + (int)entry->e_length, name); +- fprintf(fp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d", entry->attributes, +- entry->max_life, entry->max_renewable_life, entry->expiration, +- entry->pw_expiration, +- omit_nra ? 0 : entry->last_success, +- omit_nra ? 0 : entry->last_failed, ++ fprintf(fp, "%d\t%d\t%d\t%u\t%u\t%u\t%u\t%d", entry->attributes, ++ entry->max_life, entry->max_renewable_life, ++ (unsigned int)entry->expiration, ++ (unsigned int)entry->pw_expiration, ++ (unsigned int)(omit_nra ? 0 : entry->last_success), ++ (unsigned int)(omit_nra ? 0 : entry->last_failed), + omit_nra ? 0 : entry->fail_auth_count); + + /* Write out tagged data. */ +@@ -717,7 +718,7 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep, + { + int retval, nread, i, j; + krb5_db_entry *dbentry; +- int t1, t2, t3, t4, t5, t6, t7; ++ int t1, t2, t3, t4; + unsigned int u1, u2, u3, u4, u5; + char *name = NULL; + krb5_key_data *kp = NULL, *kd; +@@ -773,8 +774,8 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep, + } + + /* Get the fixed principal attributes */ +- nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t", +- &t1, &t2, &t3, &t4, &t5, &t6, &t7, &u1); ++ nread = fscanf(filep, "%d\t%d\t%d\t%u\t%u\t%d\t%d\t%d\t", ++ &t1, &t2, &t3, &u1, &u2, &u3, &u4, &u5); + if (nread != 8) { + load_err(fname, *linenop, _("cannot read principal attributes")); + goto fail; +@@ -782,11 +783,11 @@ process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep, + dbentry->attributes = t1; + dbentry->max_life = t2; + dbentry->max_renewable_life = t3; +- dbentry->expiration = t4; +- dbentry->pw_expiration = t5; +- dbentry->last_success = t6; +- dbentry->last_failed = t7; +- dbentry->fail_auth_count = u1; ++ dbentry->expiration = u1; ++ dbentry->pw_expiration = u2; ++ dbentry->last_success = u3; ++ dbentry->last_failed = u4; ++ dbentry->fail_auth_count = u5; + dbentry->mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES | + KADM5_MAX_LIFE | KADM5_MAX_RLIFE | + KADM5_PRINC_EXPIRE_TIME | KADM5_LAST_SUCCESS | +diff --git a/src/kadmin/dbutil/kdb5_mkey.c b/src/kadmin/dbutil/kdb5_mkey.c +index 7df8cbc83..2efe3176e 100644 +--- a/src/kadmin/dbutil/kdb5_mkey.c ++++ b/src/kadmin/dbutil/kdb5_mkey.c +@@ -44,8 +44,8 @@ static char *strdate(krb5_timestamp when) + { + struct tm *tm; + static char out[40]; ++ time_t lcltim = ts2tt(when); + +- time_t lcltim = when; + tm = localtime(&lcltim); + strftime(out, sizeof(out), "%a %b %d %H:%M:%S %Z %Y", tm); + return out; +@@ -481,7 +481,7 @@ kdb5_use_mkey(int argc, char *argv[]) + cur_actkvno != NULL; + prev_actkvno = cur_actkvno, cur_actkvno = cur_actkvno->next) { + +- if (new_actkvno->act_time < cur_actkvno->act_time) { ++ if (ts_after(cur_actkvno->act_time, new_actkvno->act_time)) { + if (prev_actkvno) { + prev_actkvno->next = new_actkvno; + new_actkvno->next = cur_actkvno; +@@ -499,7 +499,7 @@ kdb5_use_mkey(int argc, char *argv[]) + } + } + +- if (actkvno_list->act_time > now) { ++ if (ts_after(actkvno_list->act_time, now)) { + com_err(progname, EINVAL, + _("there must be one master key currently active")); + exit_status++; +diff --git a/src/kadmin/dbutil/tabdump.c b/src/kadmin/dbutil/tabdump.c +index 69a3482ec..fb36b060a 100644 +--- a/src/kadmin/dbutil/tabdump.c ++++ b/src/kadmin/dbutil/tabdump.c +@@ -148,7 +148,7 @@ write_date_iso(struct rec_args *args, krb5_timestamp when) + struct tm *tm = NULL; + struct rechandle *h = args->rh; + +- t = when; ++ t = ts2tt(when); + tm = gmtime(&t); + if (tm == NULL) { + errno = EINVAL; +diff --git a/src/kadmin/testing/util/tcl_kadm5.c b/src/kadmin/testing/util/tcl_kadm5.c +index a4997c60c..9dde579ef 100644 +--- a/src/kadmin/testing/util/tcl_kadm5.c ++++ b/src/kadmin/testing/util/tcl_kadm5.c +@@ -697,13 +697,13 @@ static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ, + } else + Tcl_DStringAppendElement(str, "null"); + +- sprintf(buf, "%d", princ->princ_expire_time); ++ sprintf(buf, "%u", (unsigned int)princ->princ_expire_time); + Tcl_DStringAppendElement(str, buf); + +- sprintf(buf, "%d", princ->last_pwd_change); ++ sprintf(buf, "%u", (unsigned int)princ->last_pwd_change); + Tcl_DStringAppendElement(str, buf); + +- sprintf(buf, "%d", princ->pw_expiration); ++ sprintf(buf, "%u", (unsigned int)princ->pw_expiration); + Tcl_DStringAppendElement(str, buf); + + sprintf(buf, "%d", princ->max_life); +@@ -722,7 +722,7 @@ static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ, + } else + Tcl_DStringAppendElement(str, "null"); + +- sprintf(buf, "%d", princ->mod_date); ++ sprintf(buf, "%u", (unsigned int)princ->mod_date); + Tcl_DStringAppendElement(str, buf); + + if (mask & KADM5_ATTRIBUTES) { +@@ -758,10 +758,10 @@ static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ, + sprintf(buf, "%d", princ->max_renewable_life); + Tcl_DStringAppendElement(str, buf); + +- sprintf(buf, "%d", princ->last_success); ++ sprintf(buf, "%u", (unsigned int)princ->last_success); + Tcl_DStringAppendElement(str, buf); + +- sprintf(buf, "%d", princ->last_failed); ++ sprintf(buf, "%u", (unsigned int)princ->last_failed); + Tcl_DStringAppendElement(str, buf); + + sprintf(buf, "%d", princ->fail_auth_count); +diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c +index 712ccb794..59a39cd30 100644 +--- a/src/kdc/do_as_req.c ++++ b/src/kdc/do_as_req.c +@@ -87,7 +87,7 @@ get_key_exp(krb5_db_entry *entry) + return entry->pw_expiration; + if (entry->pw_expiration == 0) + return entry->expiration; +- return min(entry->expiration, entry->pw_expiration); ++ return ts_min(entry->expiration, entry->pw_expiration); + } + + /* +diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c +index 547a41441..aacd2f20d 100644 +--- a/src/kdc/do_tgs_req.c ++++ b/src/kdc/do_tgs_req.c +@@ -500,12 +500,12 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + + old_starttime = enc_tkt_reply.times.starttime ? + enc_tkt_reply.times.starttime : enc_tkt_reply.times.authtime; +- old_life = enc_tkt_reply.times.endtime - old_starttime; ++ old_life = ts_delta(enc_tkt_reply.times.endtime, old_starttime); + + enc_tkt_reply.times.starttime = kdc_time; + enc_tkt_reply.times.endtime = +- min(header_ticket->enc_part2->times.renew_till, +- kdc_time + old_life); ++ ts_min(header_ticket->enc_part2->times.renew_till, ++ ts_incr(kdc_time, old_life)); + } else { + /* not a renew request */ + enc_tkt_reply.times.starttime = kdc_time; +diff --git a/src/kdc/extern.c b/src/kdc/extern.c +index fe627494b..84b5c6ad5 100644 +--- a/src/kdc/extern.c ++++ b/src/kdc/extern.c +@@ -37,6 +37,8 @@ + kdc_realm_t **kdc_realmlist = (kdc_realm_t **) NULL; + int kdc_numrealms = 0; + krb5_data empty_string = {0, 0, ""}; +-krb5_timestamp kdc_infinity = KRB5_INT32_MAX; /* XXX */ + krb5_keyblock psr_key; + krb5_int32 max_dgram_reply_size = MAX_DGRAM_SIZE; ++ ++/* With ts_after(), this is the largest timestamp value. */ ++krb5_timestamp kdc_infinity = -1; +diff --git a/src/kdc/fast_util.c b/src/kdc/fast_util.c +index 9df940219..e05107ef3 100644 +--- a/src/kdc/fast_util.c ++++ b/src/kdc/fast_util.c +@@ -607,7 +607,7 @@ kdc_fast_read_cookie(krb5_context context, struct kdc_request_state *state, + ret = krb5_timeofday(context, &now); + if (ret) + goto cleanup; +- if (now - COOKIE_LIFETIME > cookie->time) { ++ if (ts2tt(now) > cookie->time + COOKIE_LIFETIME) { + /* Don't accept the cookie contents. Only return an error if the + * cookie is relevant to the request. */ + if (is_relevant(cookie->data, req->padata)) +@@ -700,7 +700,7 @@ kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state, + ret = krb5_timeofday(context, &now); + if (ret) + goto cleanup; +- cookie.time = now; ++ cookie.time = ts2tt(now); + cookie.data = contents; + ret = encode_krb5_secure_cookie(&cookie, &der_cookie); + if (ret) +diff --git a/src/kdc/kdc_log.c b/src/kdc/kdc_log.c +index 94a2a1c87..c044a3553 100644 +--- a/src/kdc/kdc_log.c ++++ b/src/kdc/kdc_log.c +@@ -79,9 +79,9 @@ log_as_req(krb5_context context, const krb5_fulladdr *from, + /* success */ + char rep_etypestr[128]; + rep_etypes2str(rep_etypestr, sizeof(rep_etypestr), reply); +- krb5_klog_syslog(LOG_INFO, _("AS_REQ (%s) %s: ISSUE: authtime %d, %s, " ++ krb5_klog_syslog(LOG_INFO, _("AS_REQ (%s) %s: ISSUE: authtime %u, %s, " + "%s for %s"), +- ktypestr, fromstring, authtime, ++ ktypestr, fromstring, (unsigned int)authtime, + rep_etypestr, cname2, sname2); + } else { + /* fail */ +@@ -156,10 +156,10 @@ log_tgs_req(krb5_context ctx, const krb5_fulladdr *from, + name (useful), and doesn't log ktypestr (probably not + important). */ + if (errcode != KRB5KDC_ERR_SERVER_NOMATCH) { +- krb5_klog_syslog(LOG_INFO, _("TGS_REQ (%s) %s: %s: authtime %d, %s%s " ++ krb5_klog_syslog(LOG_INFO, _("TGS_REQ (%s) %s: %s: authtime %u, %s%s " + "%s for %s%s%s"), +- ktypestr, fromstring, status, authtime, rep_etypestr, +- !errcode ? "," : "", logcname, logsname, ++ ktypestr, fromstring, status, (unsigned int)authtime, ++ rep_etypestr, !errcode ? "," : "", logcname, logsname, + errcode ? ", " : "", errcode ? emsg : ""); + if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) + krb5_klog_syslog(LOG_INFO, +@@ -171,9 +171,9 @@ log_tgs_req(krb5_context ctx, const krb5_fulladdr *from, + logaltcname); + + } else +- krb5_klog_syslog(LOG_INFO, _("TGS_REQ %s: %s: authtime %d, %s for %s, " ++ krb5_klog_syslog(LOG_INFO, _("TGS_REQ %s: %s: authtime %u, %s for %s, " + "2nd tkt client %s"), +- fromstring, status, authtime, ++ fromstring, status, (unsigned int)authtime, + logcname, logsname, logaltcname); + + /* OpenSolaris: audit_krb5kdc_tgs_req(...) or +diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c +index 29f9dbbf0..778a629e5 100644 +--- a/src/kdc/kdc_util.c ++++ b/src/kdc/kdc_util.c +@@ -654,7 +654,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm, + } + + /* The client must not be expired */ +- if (client.expiration && client.expiration < kdc_time) { ++ if (client.expiration && ts_after(kdc_time, client.expiration)) { + *status = "CLIENT EXPIRED"; + if (vague_errors) + return(KRB_ERR_GENERIC); +@@ -664,7 +664,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm, + + /* The client's password must not be expired, unless the server is + a KRB5_KDC_PWCHANGE_SERVICE. */ +- if (client.pw_expiration && client.pw_expiration < kdc_time && ++ if (client.pw_expiration && ts_after(kdc_time, client.pw_expiration) && + !isflagset(server.attributes, KRB5_KDB_PWCHANGE_SERVICE)) { + *status = "CLIENT KEY EXPIRED"; + if (vague_errors) +@@ -674,7 +674,7 @@ validate_as_request(kdc_realm_t *kdc_active_realm, + } + + /* The server must not be expired */ +- if (server.expiration && server.expiration < kdc_time) { ++ if (server.expiration && ts_after(kdc_time, server.expiration)) { + *status = "SERVICE EXPIRED"; + return(KDC_ERR_SERVICE_EXP); + } +@@ -1765,9 +1765,9 @@ kdc_get_ticket_endtime(kdc_realm_t *kdc_active_realm, + if (till == 0) + till = kdc_infinity; + +- until = min(till, endtime); ++ until = ts_min(till, endtime); + +- life = until - starttime; ++ life = ts_delta(until, starttime); + + if (client != NULL && client->max_life != 0) + life = min(life, client->max_life); +@@ -1776,7 +1776,7 @@ kdc_get_ticket_endtime(kdc_realm_t *kdc_active_realm, + if (kdc_active_realm->realm_maxlife != 0) + life = min(life, kdc_active_realm->realm_maxlife); + +- *out_endtime = starttime + life; ++ *out_endtime = ts_incr(starttime, life); + } + + /* +@@ -1806,22 +1806,22 @@ kdc_get_ticket_renewtime(kdc_realm_t *realm, krb5_kdc_req *request, + if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) + rtime = request->rtime ? request->rtime : kdc_infinity; + else if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) && +- tkt->times.endtime < request->till) ++ ts_after(request->till, tkt->times.endtime)) + rtime = request->till; + else + return; + + /* Truncate it to the allowable renewable time. */ + if (tgt != NULL) +- rtime = min(rtime, tgt->times.renew_till); ++ rtime = ts_min(rtime, tgt->times.renew_till); + max_rlife = min(server->max_renewable_life, realm->realm_maxrlife); + if (client != NULL) + max_rlife = min(max_rlife, client->max_renewable_life); +- rtime = min(rtime, tkt->times.starttime + max_rlife); ++ rtime = ts_min(rtime, ts_incr(tkt->times.starttime, max_rlife)); + + /* Make the ticket renewable if the truncated requested time is larger than + * the ticket end time. */ +- if (rtime > tkt->times.endtime) { ++ if (ts_after(rtime, tkt->times.endtime)) { + setflag(tkt->flags, TKT_FLG_RENEWABLE); + tkt->times.renew_till = rtime; + } +diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h +index bcf05fc27..672f94380 100644 +--- a/src/kdc/kdc_util.h ++++ b/src/kdc/kdc_util.h +@@ -452,6 +452,8 @@ struct krb5_kdcpreauth_rock_st { + #define max(a, b) ((a) > (b) ? (a) : (b)) + #endif + ++#define ts_min(a, b) (ts_after(a, b) ? (b) : (a)) ++ + #define ADDRTYPE2FAMILY(X) \ + ((X) == ADDRTYPE_INET6 ? AF_INET6 : (X) == ADDRTYPE_INET ? AF_INET : -1) + +diff --git a/src/kdc/replay.c b/src/kdc/replay.c +index 8da7ac19a..fab39cf88 100644 +--- a/src/kdc/replay.c ++++ b/src/kdc/replay.c +@@ -61,7 +61,7 @@ static size_t total_size = 0; + static krb5_ui_4 seed; + + #define STALE_TIME (2*60) /* two minutes */ +-#define STALE(ptr, now) (abs((ptr)->timein - (now)) >= STALE_TIME) ++#define STALE(ptr, now) (labs(ts_delta((ptr)->timein, now)) >= STALE_TIME) + + /* Return x rotated to the left by r bits. */ + static inline krb5_ui_4 +diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c +index a30cacc66..d0f25d1b7 100644 +--- a/src/kdc/tgs_policy.c ++++ b/src/kdc/tgs_policy.c +@@ -186,7 +186,7 @@ static int + check_tgs_svc_time(krb5_kdc_req *req, krb5_db_entry server, krb5_ticket *tkt, + krb5_timestamp kdc_time, const char **status) + { +- if (server.expiration && server.expiration < kdc_time) { ++ if (server.expiration && ts_after(kdc_time, server.expiration)) { + *status = "SERVICE EXPIRED"; + return KDC_ERR_SERVICE_EXP; + } +@@ -222,7 +222,7 @@ check_tgs_times(krb5_kdc_req *req, krb5_ticket_times *times, + KDC time. */ + if (req->kdc_options & KDC_OPT_VALIDATE) { + starttime = times->starttime ? times->starttime : times->authtime; +- if (starttime > kdc_time) { ++ if (ts_after(starttime, kdc_time)) { + *status = "NOT_YET_VALID"; + return KRB_AP_ERR_TKT_NYV; + } +@@ -231,7 +231,8 @@ check_tgs_times(krb5_kdc_req *req, krb5_ticket_times *times, + * Check the renew_till time. The endtime was already + * been checked in the initial authentication check. + */ +- if ((req->kdc_options & KDC_OPT_RENEW) && times->renew_till < kdc_time) { ++ if ((req->kdc_options & KDC_OPT_RENEW) && ++ ts_after(kdc_time, times->renew_till)) { + *status = "TKT_EXPIRED"; + return KRB_AP_ERR_TKT_EXPIRED; + } +diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c +index 580d08cbf..06967aa27 100644 +--- a/src/lib/gssapi/krb5/accept_sec_context.c ++++ b/src/lib/gssapi/krb5/accept_sec_context.c +@@ -351,8 +351,10 @@ kg_accept_dce(minor_status, context_handle, verifier_cred_handle, + if (mech_type) + *mech_type = ctx->mech_used; + +- if (time_rec) +- *time_rec = ctx->krb_times.endtime + ctx->k5_context->clockskew - now; ++ if (time_rec) { ++ *time_rec = ts_delta(ctx->krb_times.endtime, now) + ++ ctx->k5_context->clockskew; ++ } + + /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential + * delegation yet. */ +@@ -1146,7 +1148,7 @@ kg_accept_krb5(minor_status, context_handle, + /* Add the maximum allowable clock skew as a grace period for context + * expiration, just as we do for the ticket. */ + if (time_rec) +- *time_rec = ctx->krb_times.endtime + context->clockskew - now; ++ *time_rec = ts_delta(ctx->krb_times.endtime, now) + context->clockskew; + + if (ret_flags) + *ret_flags = ctx->gss_flags; +diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c +index 03ee25ec1..362ba9d86 100644 +--- a/src/lib/gssapi/krb5/acquire_cred.c ++++ b/src/lib/gssapi/krb5/acquire_cred.c +@@ -550,7 +550,7 @@ set_refresh_time(krb5_context context, krb5_ccache ccache, + char buf[128]; + krb5_data d; + +- snprintf(buf, sizeof(buf), "%ld", (long)refresh_time); ++ snprintf(buf, sizeof(buf), "%u", (unsigned int)ts2tt(refresh_time)); + d = string2data(buf); + (void)krb5_cc_set_config(context, ccache, NULL, KRB5_CC_CONF_REFRESH_TIME, + &d); +@@ -566,8 +566,9 @@ kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred) + + if (krb5_timeofday(context, &now)) + return FALSE; +- if (cred->refresh_time != 0 && now >= cred->refresh_time) { +- set_refresh_time(context, cred->ccache, cred->refresh_time + 30); ++ if (cred->refresh_time != 0 && !ts_after(cred->refresh_time, now)) { ++ set_refresh_time(context, cred->ccache, ++ ts_incr(cred->refresh_time, 30)); + return TRUE; + } + return FALSE; +@@ -586,7 +587,8 @@ kg_cred_set_initial_refresh(krb5_context context, krb5_gss_cred_id_rec *cred, + return; + + /* Make a note to refresh these when they are halfway to expired. */ +- refresh = times->starttime + (times->endtime - times->starttime) / 2; ++ refresh = ts_incr(times->starttime, ++ ts_delta(times->endtime, times->starttime) / 2); + set_refresh_time(context, cred->ccache, refresh); + } + +@@ -848,7 +850,8 @@ acquire_cred_context(krb5_context context, OM_uint32 *minor_status, + GSS_C_NO_NAME); + if (GSS_ERROR(ret)) + goto error_out; +- *time_rec = (cred->expire > now) ? (cred->expire - now) : 0; ++ *time_rec = ts_after(cred->expire, now) ? ++ ts_delta(cred->expire, now) : 0; + k5_mutex_unlock(&cred->lock); + } + } +diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c +index 450593288..1fdb5a16f 100644 +--- a/src/lib/gssapi/krb5/context_time.c ++++ b/src/lib/gssapi/krb5/context_time.c +@@ -51,7 +51,7 @@ krb5_gss_context_time(minor_status, context_handle, time_rec) + return(GSS_S_FAILURE); + } + +- lifetime = ctx->krb_times.endtime - now; ++ lifetime = ts_delta(ctx->krb_times.endtime, now); + if (!ctx->initiate) + lifetime += ctx->k5_context->clockskew; + if (lifetime <= 0) { +diff --git a/src/lib/gssapi/krb5/export_cred.c b/src/lib/gssapi/krb5/export_cred.c +index 652b2604b..8054e4a77 100644 +--- a/src/lib/gssapi/krb5/export_cred.c ++++ b/src/lib/gssapi/krb5/export_cred.c +@@ -410,10 +410,11 @@ json_kgcred(krb5_context context, krb5_gss_cred_id_t cred, + if (ret) + goto cleanup; + +- ret = k5_json_array_fmt(&array, "ivvbbvvvvbiivs", cred->usage, name, imp, ++ ret = k5_json_array_fmt(&array, "ivvbbvvvvbLLvs", cred->usage, name, imp, + cred->default_identity, cred->iakerb_mech, keytab, + rcache, ccache, ckeytab, cred->have_tgt, +- cred->expire, cred->refresh_time, etypes, ++ (long long)ts2tt(cred->expire), ++ (long long)ts2tt(cred->refresh_time), etypes, + cred->password); + if (ret) + goto cleanup; +diff --git a/src/lib/gssapi/krb5/iakerb.c b/src/lib/gssapi/krb5/iakerb.c +index 2dc4d0c1a..bb1072fe4 100644 +--- a/src/lib/gssapi/krb5/iakerb.c ++++ b/src/lib/gssapi/krb5/iakerb.c +@@ -494,7 +494,7 @@ iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx, + if (code != 0) + goto cleanup; + +- creds.times.endtime = now + time_req; ++ creds.times.endtime = ts_incr(now, time_req); + } + + if (cred->name->ad_context != NULL) { +@@ -669,7 +669,7 @@ iakerb_get_initial_state(iakerb_ctx_id_t ctx, + if (code != 0) + goto cleanup; + +- in_creds.times.endtime = now + time_req; ++ in_creds.times.endtime = ts_incr(now, time_req); + } + + /* Make an AS request if we have no creds or it's time to refresh them. */ +diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c +index 70f7955ae..8e5cc37fb 100644 +--- a/src/lib/gssapi/krb5/init_sec_context.c ++++ b/src/lib/gssapi/krb5/init_sec_context.c +@@ -214,7 +214,8 @@ static krb5_error_code get_credentials(context, cred, server, now, + * boundaries) because accept_sec_context code is also similarly + * non-forgiving. + */ +- if (!krb5_gss_dbg_client_expcreds && result_creds->times.endtime < now) { ++ if (!krb5_gss_dbg_client_expcreds && ++ ts_after(now, result_creds->times.endtime)) { + code = KRB5KRB_AP_ERR_TKT_EXPIRED; + goto cleanup; + } +@@ -575,7 +576,7 @@ kg_new_connection( + if (time_req == 0 || time_req == GSS_C_INDEFINITE) { + ctx->krb_times.endtime = 0; + } else { +- ctx->krb_times.endtime = now + time_req; ++ ctx->krb_times.endtime = ts_incr(now, time_req); + } + + if ((code = kg_duplicate_name(context, cred->name, &ctx->here))) +@@ -659,7 +660,7 @@ kg_new_connection( + if (time_rec) { + if ((code = krb5_timeofday(context, &now))) + goto cleanup; +- *time_rec = ctx->krb_times.endtime - now; ++ *time_rec = ts_delta(ctx->krb_times.endtime, now); + } + + /* set the other returns */ +@@ -873,7 +874,7 @@ mutual_auth( + if (time_rec) { + if ((code = krb5_timeofday(context, &now))) + goto fail; +- *time_rec = ctx->krb_times.endtime - now; ++ *time_rec = ts_delta(ctx->krb_times.endtime, now); + } + + if (ret_flags) +diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c +index d2e466e60..cac024da1 100644 +--- a/src/lib/gssapi/krb5/inq_context.c ++++ b/src/lib/gssapi/krb5/inq_context.c +@@ -120,7 +120,7 @@ krb5_gss_inquire_context(minor_status, context_handle, initiator_name, + + /* Add the maximum allowable clock skew as a grace period for context + * expiration, just as we do for the ticket during authentication. */ +- lifetime = ctx->krb_times.endtime - now; ++ lifetime = ts_delta(ctx->krb_times.endtime, now); + if (!ctx->initiate) + lifetime += context->clockskew; + if (lifetime < 0) +diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c +index 4e35a0563..e662ae53a 100644 +--- a/src/lib/gssapi/krb5/inq_cred.c ++++ b/src/lib/gssapi/krb5/inq_cred.c +@@ -130,8 +130,9 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, + goto fail; + } + +- if (cred->expire > 0) { +- if ((lifetime = cred->expire - now) < 0) ++ if (cred->expire != 0) { ++ lifetime = ts_delta(cred->expire, now); ++ if (lifetime < 0) + lifetime = 0; + } + else +diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c +index ff1c310bc..10848c1df 100644 +--- a/src/lib/gssapi/krb5/s4u_gss_glue.c ++++ b/src/lib/gssapi/krb5/s4u_gss_glue.c +@@ -284,7 +284,7 @@ kg_compose_deleg_cred(OM_uint32 *minor_status, + if (code != 0) + goto cleanup; + +- *time_rec = cred->expire - now; ++ *time_rec = ts_delta(cred->expire, now); + } + + major_status = GSS_S_COMPLETE; +diff --git a/src/lib/kadm5/chpass_util.c b/src/lib/kadm5/chpass_util.c +index 408b0eb31..1680a5504 100644 +--- a/src/lib/kadm5/chpass_util.c ++++ b/src/lib/kadm5/chpass_util.c +@@ -4,15 +4,11 @@ + */ + + +-#include "autoconf.h" +-#include +-#include +-#include ++#include "k5-int.h" + + #include + #include "admin_internal.h" + +-#include + + #define string_text error_message + +@@ -218,7 +214,7 @@ kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle, + time_t until; + char *time_string, *ptr; + +- until = princ_ent.last_pwd_change + policy_ent.pw_min_life; ++ until = ts_incr(princ_ent.last_pwd_change, policy_ent.pw_min_life); + + time_string = ctime(&until); + if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') +diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c +index 59ed0b975..656dddff5 100644 +--- a/src/lib/kadm5/srv/server_acl.c ++++ b/src/lib/kadm5/srv/server_acl.c +@@ -408,13 +408,14 @@ kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp) + } + if (rp->mask & KADM5_PRINC_EXPIRE_TIME) { + if (!(*maskp & KADM5_PRINC_EXPIRE_TIME) +- || (recp->princ_expire_time > (now + rp->princ_lifetime))) ++ || ts_after(recp->princ_expire_time, ++ ts_incr(now, rp->princ_lifetime))) + recp->princ_expire_time = now + rp->princ_lifetime; + *maskp |= KADM5_PRINC_EXPIRE_TIME; + } + if (rp->mask & KADM5_PW_EXPIRATION) { + if (!(*maskp & KADM5_PW_EXPIRATION) +- || (recp->pw_expiration > (now + rp->pw_lifetime))) ++ || ts_after(recp->pw_expiration, ts_incr(now, rp->pw_lifetime))) + recp->pw_expiration = now + rp->pw_lifetime; + *maskp |= KADM5_PW_EXPIRATION; + } +diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c +index 0640b47c4..f4a9a2ad2 100644 +--- a/src/lib/kadm5/srv/svr_principal.c ++++ b/src/lib/kadm5/srv/svr_principal.c +@@ -400,7 +400,7 @@ kadm5_create_principal_3(void *server_handle, + kdb->pw_expiration = 0; + if (have_polent) { + if(polent.pw_max_life) +- kdb->pw_expiration = now + polent.pw_max_life; ++ kdb->pw_expiration = ts_incr(now, polent.pw_max_life); + else + kdb->pw_expiration = 0; + } +@@ -612,7 +612,7 @@ kadm5_modify_principal(void *server_handle, + &(kdb->pw_expiration)); + if (ret) + goto done; +- kdb->pw_expiration += pol.pw_max_life; ++ kdb->pw_expiration = ts_incr(kdb->pw_expiration, pol.pw_max_life); + } else { + kdb->pw_expiration = 0; + } +@@ -1445,7 +1445,7 @@ kadm5_chpass_principal_3(void *server_handle, + } + + if (pol.pw_max_life) +- kdb->pw_expiration = now + pol.pw_max_life; ++ kdb->pw_expiration = ts_incr(now, pol.pw_max_life); + else + kdb->pw_expiration = 0; + } else { +@@ -1624,7 +1624,7 @@ kadm5_randkey_principal_3(void *server_handle, + #endif + + if (pol.pw_max_life) +- kdb->pw_expiration = now + pol.pw_max_life; ++ kdb->pw_expiration = ts_incr(now, pol.pw_max_life); + else + kdb->pw_expiration = 0; + } else { +@@ -1774,7 +1774,7 @@ kadm5_setv4key_principal(void *server_handle, + #endif + + if (pol.pw_max_life) +- kdb->pw_expiration = now + pol.pw_max_life; ++ kdb->pw_expiration = ts_incr(now, pol.pw_max_life); + else + kdb->pw_expiration = 0; + } else { +@@ -2024,7 +2024,7 @@ kadm5_setkey_principal_4(void *server_handle, krb5_principal principal, + } + if (have_pol) { + if (pol.pw_max_life) +- kdb->pw_expiration = now + pol.pw_max_life; ++ kdb->pw_expiration = ts_incr(now, pol.pw_max_life); + else + kdb->pw_expiration = 0; + } else { +diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c +index 4adf0fcbb..7f33c7e68 100644 +--- a/src/lib/kdb/kdb5.c ++++ b/src/lib/kdb/kdb5.c +@@ -1296,7 +1296,7 @@ find_actkvno(krb5_actkvno_node *list, krb5_timestamp now) + * are in the future, we will return the first node; if all are in the + * past, we will return the last node. + */ +- while (list->next != NULL && list->next->act_time <= now) ++ while (list->next != NULL && !ts_after(list->next->act_time, now)) + list = list->next; + return list->act_kvno; + } +diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c +index a827ca608..889460989 100644 +--- a/src/lib/krb5/asn.1/asn1_k_encode.c ++++ b/src/lib/krb5/asn.1/asn1_k_encode.c +@@ -158,8 +158,7 @@ static asn1_error_code + encode_kerberos_time(asn1buf *buf, const void *p, taginfo *rettag, + size_t *len_out) + { +- /* Range checking for time_t vs krb5_timestamp? */ +- time_t val = *(krb5_timestamp *)p; ++ time_t val = ts2tt(*(krb5_timestamp *)p); + rettag->asn1class = UNIVERSAL; + rettag->construction = PRIMITIVE; + rettag->tagnum = ASN1_GENERALTIME; +diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c +index 4fe3f0d6f..fba710b1b 100644 +--- a/src/lib/krb5/ccache/cc_keyring.c ++++ b/src/lib/krb5/ccache/cc_keyring.c +@@ -751,7 +751,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id) + for (;;) { + if (krcc_next_cred(context, id, &cursor, &creds) != 0) + break; +- if (creds.times.endtime > endtime) ++ if (ts_after(creds.times.endtime, endtime)) + endtime = creds.times.endtime; + krb5_free_cred_contents(context, &creds); + } +@@ -765,7 +765,7 @@ update_keyring_expiration(krb5_context context, krb5_ccache id) + + /* Setting the timeout to zero would reset the timeout, so we set it to one + * second instead if creds are already expired. */ +- timeout = (endtime > now) ? endtime - now : 1; ++ timeout = ts_after(endtime, now) ? ts_delta(endtime, now) : 1; + (void)keyctl_set_timeout(data->cache_id, timeout); + } + +@@ -1316,8 +1316,10 @@ krcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds) + if (ret) + goto errout; + +- if (creds->times.endtime > now) +- (void)keyctl_set_timeout(cred_key, creds->times.endtime - now); ++ if (ts_after(creds->times.endtime, now)) { ++ (void)keyctl_set_timeout(cred_key, ++ ts_delta(creds->times.endtime, now)); ++ } + + update_keyring_expiration(context, id); + +@@ -1680,8 +1682,8 @@ static void + krcc_update_change_time(krcc_data *data) + { + krb5_timestamp now_time = time(NULL); +- data->changetime = (data->changetime >= now_time) ? +- data->changetime + 1 : now_time; ++ data->changetime = ts_after(now_time, data->changetime) ? ++ now_time : ts_incr(data->changetime, 1); + } + + /* +diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c +index 0354575c5..c5425eb3a 100644 +--- a/src/lib/krb5/ccache/cc_memory.c ++++ b/src/lib/krb5/ccache/cc_memory.c +@@ -720,8 +720,8 @@ static void + update_mcc_change_time(krb5_mcc_data *d) + { + krb5_timestamp now_time = time(NULL); +- d->changetime = (d->changetime >= now_time) ? +- d->changetime + 1 : now_time; ++ d->changetime = ts_after(now_time, d->changetime) ? ++ now_time : ts_incr(d->changetime, 1); + } + + static krb5_error_code KRB5_CALLCONV +diff --git a/src/lib/krb5/ccache/cc_retr.c b/src/lib/krb5/ccache/cc_retr.c +index 1314d24bd..1a32e00c8 100644 +--- a/src/lib/krb5/ccache/cc_retr.c ++++ b/src/lib/krb5/ccache/cc_retr.c +@@ -46,11 +46,11 @@ static krb5_boolean + times_match(const krb5_ticket_times *t1, const krb5_ticket_times *t2) + { + if (t1->renew_till) { +- if (t1->renew_till > t2->renew_till) ++ if (ts_after(t1->renew_till, t2->renew_till)) + return FALSE; /* this one expires too late */ + } + if (t1->endtime) { +- if (t1->endtime > t2->endtime) ++ if (ts_after(t1->endtime, t2->endtime)) + return FALSE; /* this one expires too late */ + } + /* only care about expiration on a times_match */ +diff --git a/src/lib/krb5/ccache/ccapi/stdcc_util.c b/src/lib/krb5/ccache/ccapi/stdcc_util.c +index 9f44af3d0..6092ee432 100644 +--- a/src/lib/krb5/ccache/ccapi/stdcc_util.c ++++ b/src/lib/krb5/ccache/ccapi/stdcc_util.c +@@ -16,8 +16,8 @@ + #include + #endif + ++#include "k5-int.h" + #include "stdcc_util.h" +-#include "krb5.h" + #ifdef _WIN32 /* it's part of krb5.h everywhere else */ + #include "kv5m_err.h" + #endif +@@ -321,10 +321,10 @@ copy_cc_cred_union_to_krb5_creds (krb5_context in_context, + keyblock_contents = NULL; + + /* copy times */ +- out_creds->times.authtime = cv5->authtime + offset_seconds; +- out_creds->times.starttime = cv5->starttime + offset_seconds; +- out_creds->times.endtime = cv5->endtime + offset_seconds; +- out_creds->times.renew_till = cv5->renew_till + offset_seconds; ++ out_creds->times.authtime = ts_incr(cv5->authtime, offset_seconds); ++ out_creds->times.starttime = ts_incr(cv5->starttime, offset_seconds); ++ out_creds->times.endtime = ts_incr(cv5->endtime, offset_seconds); ++ out_creds->times.renew_till = ts_incr(cv5->renew_till, offset_seconds); + out_creds->is_skey = cv5->is_skey; + out_creds->ticket_flags = cv5->ticket_flags; + +@@ -451,11 +451,11 @@ copy_krb5_creds_to_cc_cred_union (krb5_context in_context, + cv5->keyblock.data = keyblock_data; + keyblock_data = NULL; + +- cv5->authtime = in_creds->times.authtime - offset_seconds; +- cv5->starttime = in_creds->times.starttime - offset_seconds; +- cv5->endtime = in_creds->times.endtime - offset_seconds; +- cv5->renew_till = in_creds->times.renew_till - offset_seconds; +- cv5->is_skey = in_creds->is_skey; ++ cv5->authtime = ts_incr(in_creds->times.authtime, -offset_seconds); ++ cv5->starttime = ts_incr(in_creds->times.starttime, -offset_seconds); ++ cv5->endtime = ts_incr(in_creds->times.endtime, -offset_seconds); ++ cv5->renew_till = ts_incr(in_creds->times.renew_till, -offset_seconds); ++ cv5->is_skey = in_creds->is_skey; + cv5->ticket_flags = in_creds->ticket_flags; + + if (in_creds->ticket.data) { +@@ -732,10 +732,10 @@ void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest) + err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); + if (err) return; + #endif +- dest->times.authtime = src->authtime + offset_seconds; +- dest->times.starttime = src->starttime + offset_seconds; +- dest->times.endtime = src->endtime + offset_seconds; +- dest->times.renew_till = src->renew_till + offset_seconds; ++ dest->times.authtime = ts_incr(src->authtime, offset_seconds); ++ dest->times.starttime = ts_incr(src->starttime, offset_seconds); ++ dest->times.endtime = ts_incr(src->endtime, offset_seconds); ++ dest->times.renew_till = ts_incr(src->renew_till, offset_seconds); + dest->is_skey = src->is_skey; + dest->ticket_flags = src->ticket_flags; + +@@ -804,10 +804,10 @@ void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu) + err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); + if (err) return; + #endif +- c->authtime = creds->times.authtime - offset_seconds; +- c->starttime = creds->times.starttime - offset_seconds; +- c->endtime = creds->times.endtime - offset_seconds; +- c->renew_till = creds->times.renew_till - offset_seconds; ++ c->authtime = ts_incr(creds->times.authtime, -offset_seconds); ++ c->starttime = ts_incr(creds->times.starttime, -offset_seconds); ++ c->endtime = ts_incr(creds->times.endtime, -offset_seconds); ++ c->renew_till = ts_incr(creds->times.renew_till, -offset_seconds); + c->is_skey = creds->is_skey; + c->ticket_flags = creds->ticket_flags; + +@@ -925,11 +925,11 @@ times_match(t1, t2) + register const krb5_ticket_times *t2; + { + if (t1->renew_till) { +- if (t1->renew_till > t2->renew_till) ++ if (ts_after(t1->renew_till, t2->renew_till)) + return FALSE; /* this one expires too late */ + } + if (t1->endtime) { +- if (t1->endtime > t2->endtime) ++ if (ts_after(t1->endtime, t2->endtime)) + return FALSE; /* this one expires too late */ + } + /* only care about expiration on a times_match */ +diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c +index c31a3f5f0..e631f2051 100644 +--- a/src/lib/krb5/ccache/cccursor.c ++++ b/src/lib/krb5/ccache/cccursor.c +@@ -159,7 +159,7 @@ krb5_cccol_last_change_time(krb5_context context, + ret = krb5_cccol_cursor_next(context, c, &ccache); + if (ccache) { + ret = krb5_cc_last_change_time(context, ccache, &last_time); +- if (!ret && last_time > max_change_time) { ++ if (!ret && ts_after(last_time, max_change_time)) { + max_change_time = last_time; + } + ret = 0; +diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c +index 131549ffe..b014abf0b 100644 +--- a/src/lib/krb5/keytab/kt_file.c ++++ b/src/lib/krb5/keytab/kt_file.c +@@ -264,9 +264,11 @@ more_recent(const krb5_keytab_entry *k1, const krb5_keytab_entry *k2) + * limitations (8-bit kvno storage), pre-1.14 kadmin protocol limitations + * (8-bit kvno marshalling), or KDB limitations (16-bit kvno storage). + */ +- if (k1->timestamp >= k2->timestamp && k1->vno < 128 && k2->vno > 240) ++ if (!ts_after(k2->timestamp, k1->timestamp) && ++ k1->vno < 128 && k2->vno > 240) + return TRUE; +- if (k1->timestamp <= k2->timestamp && k1->vno > 240 && k2->vno < 128) ++ if (!ts_after(k1->timestamp, k2->timestamp) && ++ k1->vno > 240 && k2->vno < 128) + return FALSE; + + /* Otherwise do a simple version comparison. */ +diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c +index c85d8b8d8..cf1ea361f 100644 +--- a/src/lib/krb5/krb/gc_via_tkt.c ++++ b/src/lib/krb5/krb/gc_via_tkt.c +@@ -287,18 +287,19 @@ krb5int_process_tgs_reply(krb5_context context, + retval = KRB5_KDCREP_MODIFIED; + + if ((in_cred->times.endtime != 0) && +- (dec_rep->enc_part2->times.endtime > in_cred->times.endtime)) ++ ts_after(dec_rep->enc_part2->times.endtime, in_cred->times.endtime)) + retval = KRB5_KDCREP_MODIFIED; + + if ((kdcoptions & KDC_OPT_RENEWABLE) && + (in_cred->times.renew_till != 0) && +- (dec_rep->enc_part2->times.renew_till > in_cred->times.renew_till)) ++ ts_after(dec_rep->enc_part2->times.renew_till, ++ in_cred->times.renew_till)) + retval = KRB5_KDCREP_MODIFIED; + + if ((kdcoptions & KDC_OPT_RENEWABLE_OK) && + (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) && + (in_cred->times.endtime != 0) && +- (dec_rep->enc_part2->times.renew_till > in_cred->times.endtime)) ++ ts_after(dec_rep->enc_part2->times.renew_till, in_cred->times.endtime)) + retval = KRB5_KDCREP_MODIFIED; + + if (retval != 0) +diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c +index 110abeb2b..be5b2d18c 100644 +--- a/src/lib/krb5/krb/get_creds.c ++++ b/src/lib/krb5/krb/get_creds.c +@@ -816,7 +816,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx, + return code; + + /* Check if the TGT is expired before bothering the KDC with it. */ +- if (now > tgt->times.endtime) { ++ if (ts_after(now, tgt->times.endtime)) { + krb5_free_creds(context, tgt); + return KRB5KRB_AP_ERR_TKT_EXPIRED; + } +diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c +index a058f5bd7..40aba1905 100644 +--- a/src/lib/krb5/krb/get_in_tkt.c ++++ b/src/lib/krb5/krb/get_in_tkt.c +@@ -39,24 +39,6 @@ static krb5_error_code sort_krb5_padata_sequence(krb5_context context, + krb5_data *realm, + krb5_pa_data **padata); + +-/* +- * This function performs 32 bit bounded addition so we can generate +- * lifetimes without overflowing krb5_int32 +- */ +-static krb5_int32 +-krb5int_addint32 (krb5_int32 x, krb5_int32 y) +-{ +- if ((x > 0) && (y > (KRB5_INT32_MAX - x))) { +- /* sum will be be greater than KRB5_INT32_MAX */ +- return KRB5_INT32_MAX; +- } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) { +- /* sum will be less than KRB5_INT32_MIN */ +- return KRB5_INT32_MIN; +- } +- +- return x + y; +-} +- + /* + * Decrypt the AS reply in ctx, populating ctx->reply->enc_part2. If + * strengthen_key is not null, combine it with the reply key as specified in +@@ -267,21 +249,21 @@ verify_as_reply(krb5_context context, + (request->from != 0) && + (request->from != as_reply->enc_part2->times.starttime)) + || ((request->till != 0) && +- (as_reply->enc_part2->times.endtime > request->till)) ++ ts_after(as_reply->enc_part2->times.endtime, request->till)) + || ((request->kdc_options & KDC_OPT_RENEWABLE) && + (request->rtime != 0) && +- (as_reply->enc_part2->times.renew_till > request->rtime)) ++ ts_after(as_reply->enc_part2->times.renew_till, request->rtime)) + || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) && + !(request->kdc_options & KDC_OPT_RENEWABLE) && + (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && + (request->till != 0) && +- (as_reply->enc_part2->times.renew_till > request->till)) ++ ts_after(as_reply->enc_part2->times.renew_till, request->till)) + ) { + return KRB5_KDCREP_MODIFIED; + } + + if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) { +- time_offset = as_reply->enc_part2->times.authtime - time_now; ++ time_offset = ts_delta(as_reply->enc_part2->times.authtime, time_now); + retval = krb5_set_time_offsets(context, time_offset, 0); + if (retval) + return retval; +@@ -790,15 +772,15 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx) + return code; + + /* Omit request start time unless the caller explicitly asked for one. */ +- from = krb5int_addint32(now, ctx->start_time); ++ from = ts_incr(now, ctx->start_time); + if (ctx->start_time != 0) + ctx->request->from = from; + +- ctx->request->till = krb5int_addint32(from, ctx->tkt_life); ++ ctx->request->till = ts_incr(from, ctx->tkt_life); + + if (ctx->renew_life > 0) { + /* Don't ask for a smaller renewable time than the lifetime. */ +- ctx->request->rtime = krb5int_addint32(from, ctx->renew_life); ++ ctx->request->rtime = ts_incr(from, ctx->renew_life); + if (ctx->request->rtime < ctx->request->till) + ctx->request->rtime = ctx->request->till; + ctx->request->kdc_options &= ~KDC_OPT_RENEWABLE_OK; +@@ -1438,7 +1420,7 @@ note_req_timestamp(krb5_context context, krb5_init_creds_context ctx, + + if (k5_time_with_offset(0, 0, &now, &usec) != 0) + return; +- ctx->pa_offset = kdc_time - now; ++ ctx->pa_offset = ts_delta(kdc_time, now); + ctx->pa_offset_usec = kdc_usec - usec; + ctx->pa_offset_state = (ctx->fast_state->armor_key != NULL) ? + AUTH_OFFSET : UNAUTH_OFFSET; +@@ -1807,6 +1789,7 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out, + { + int i; + krb5_int32 starttime; ++ krb5_deltat lifetime; + krb5_get_init_creds_opt *opt; + krb5_error_code retval; + +@@ -1838,7 +1821,8 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out, + if (retval) + goto cleanup; + if (creds->times.starttime) starttime = creds->times.starttime; +- krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime); ++ lifetime = ts_delta(creds->times.endtime, starttime); ++ krb5_get_init_creds_opt_set_tkt_life(opt, lifetime); + } + *out = opt; + return 0; +diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c +index 6f3a29f2c..3565a7c4c 100644 +--- a/src/lib/krb5/krb/gic_pwd.c ++++ b/src/lib/krb5/krb/gic_pwd.c +@@ -211,7 +211,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, + if (ret != 0) + return; + if (!is_last_req && +- (pw_exp < now || (pw_exp - now) > 7 * 24 * 60 * 60)) ++ (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60)) + return; + + if (!prompter) +@@ -221,7 +221,7 @@ warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options, + if (ret != 0) + return; + +- delta = pw_exp - now; ++ delta = ts_delta(pw_exp, now); + if (delta < 3600) { + snprintf(banner, sizeof(banner), + _("Warning: Your password will expire in less than one hour " +diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h +index 44eca359f..48bd9f8f7 100644 +--- a/src/lib/krb5/krb/int-proto.h ++++ b/src/lib/krb5/krb/int-proto.h +@@ -84,7 +84,7 @@ krb5int_construct_matching_creds(krb5_context context, krb5_flags options, + krb5_flags *fields); + + #define in_clock_skew(context, date, now) \ +- (labs((date) - (now)) < (context)->clockskew) ++ (labs(ts_delta(date, now)) < (context)->clockskew) + + #define IS_TGS_PRINC(p) ((p)->length == 2 && \ + data_eq_string((p)->data[0], KRB5_TGS_NAME)) +diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c +index 9098927b5..c70585a9e 100644 +--- a/src/lib/krb5/krb/pac.c ++++ b/src/lib/krb5/krb/pac.c +@@ -378,7 +378,7 @@ k5_time_to_seconds_since_1970(int64_t ntTime, krb5_timestamp *elapsedSeconds) + + abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime; + +- if (abstime > KRB5_INT32_MAX) ++ if (abstime > UINT32_MAX) + return ERANGE; + + *elapsedSeconds = abstime; +diff --git a/src/lib/krb5/krb/str_conv.c b/src/lib/krb5/krb/str_conv.c +index 3ab7eacac..f0a2ae20b 100644 +--- a/src/lib/krb5/krb/str_conv.c ++++ b/src/lib/krb5/krb/str_conv.c +@@ -207,7 +207,7 @@ krb5_error_code KRB5_CALLCONV + krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen) + { + size_t ret; +- time_t timestamp2 = timestamp; ++ time_t timestamp2 = ts2tt(timestamp); + struct tm tmbuf; + const char *fmt = "%c"; /* This is to get around gcc -Wall warning that + the year returned might be two digits */ +@@ -229,7 +229,7 @@ krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen + struct tm *tmp; + size_t i; + size_t ndone; +- time_t timestamp2 = timestamp; ++ time_t timestamp2 = ts2tt(timestamp); + struct tm tmbuf; + + static const char * const sftime_format_table[] = { +diff --git a/src/lib/krb5/krb/t_kerb.c b/src/lib/krb5/krb/t_kerb.c +index 60cfb5b15..74ac14d9a 100644 +--- a/src/lib/krb5/krb/t_kerb.c ++++ b/src/lib/krb5/krb/t_kerb.c +@@ -5,16 +5,8 @@ + */ + + #include "autoconf.h" +-#include "krb5.h" +-#include +-#include +-#include +-#include ++#include "k5-int.h" + #include +-#include +-#include +-#include +-#include + + #include "com_err.h" + +@@ -37,7 +29,7 @@ test_string_to_timestamp(krb5_context ctx, char *ktime) + com_err("krb5_string_to_timestamp", retval, 0); + return; + } +- t = (time_t) timestamp; ++ t = ts2tt(timestamp); + printf("Parsed time was %s", ctime(&t)); + } + +diff --git a/src/lib/krb5/krb/valid_times.c b/src/lib/krb5/krb/valid_times.c +index d63122183..9e509b2dd 100644 +--- a/src/lib/krb5/krb/valid_times.c ++++ b/src/lib/krb5/krb/valid_times.c +@@ -47,10 +47,10 @@ krb5int_validate_times(krb5_context context, krb5_ticket_times *times) + else + starttime = times->authtime; + +- if (starttime - currenttime > context->clockskew) ++ if (ts_delta(starttime, currenttime) > context->clockskew) + return KRB5KRB_AP_ERR_TKT_NYV; /* ticket not yet valid */ + +- if ((currenttime - times->endtime) > context->clockskew) ++ if (ts_delta(currenttime, times->endtime) > context->clockskew) + return KRB5KRB_AP_ERR_TKT_EXPIRED; /* ticket expired */ + + return 0; +diff --git a/src/lib/krb5/krb/vfy_increds.c b/src/lib/krb5/krb/vfy_increds.c +index 9786d63b5..b4878ba38 100644 +--- a/src/lib/krb5/krb/vfy_increds.c ++++ b/src/lib/krb5/krb/vfy_increds.c +@@ -120,7 +120,7 @@ get_vfy_cred(krb5_context context, krb5_creds *creds, krb5_principal server, + ret = krb5_timeofday(context, &in_creds.times.endtime); + if (ret) + goto cleanup; +- in_creds.times.endtime += 5*60; ++ in_creds.times.endtime = ts_incr(in_creds.times.endtime, 5 * 60); + ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds); + if (ret) + goto cleanup; +diff --git a/src/lib/krb5/os/timeofday.c b/src/lib/krb5/os/timeofday.c +index fddb12142..887f24c22 100644 +--- a/src/lib/krb5/os/timeofday.c ++++ b/src/lib/krb5/os/timeofday.c +@@ -60,7 +60,7 @@ krb5_check_clockskew(krb5_context context, krb5_timestamp date) + retval = krb5_timeofday(context, ¤ttime); + if (retval) + return retval; +- if (!(labs((date)-currenttime) < context->clockskew)) ++ if (labs(ts_delta(date, currenttime)) >= context->clockskew) + return KRB5KRB_AP_ERR_SKEW; + + return 0; +diff --git a/src/lib/krb5/os/toffset.c b/src/lib/krb5/os/toffset.c +index 456193a41..37bc69f49 100644 +--- a/src/lib/krb5/os/toffset.c ++++ b/src/lib/krb5/os/toffset.c +@@ -47,7 +47,7 @@ krb5_set_real_time(krb5_context context, krb5_timestamp seconds, krb5_int32 micr + if (retval) + return retval; + +- os_ctx->time_offset = seconds - sec; ++ os_ctx->time_offset = ts_delta(seconds, sec); + os_ctx->usec_offset = (microseconds > -1) ? microseconds - usec : 0; + + os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) | +diff --git a/src/lib/krb5/os/ustime.c b/src/lib/krb5/os/ustime.c +index 056357683..1c1b571eb 100644 +--- a/src/lib/krb5/os/ustime.c ++++ b/src/lib/krb5/os/ustime.c +@@ -49,13 +49,13 @@ k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec, + usec += offset_usec; + if (usec > 1000000) { + usec -= 1000000; +- sec++; ++ sec = ts_incr(sec, 1); + } + if (usec < 0) { + usec += 1000000; +- sec--; ++ sec = ts_incr(sec, -1); + } +- sec += offset; ++ sec = ts_incr(sec, offset); + + *time_out = sec; + *usec_out = usec; +diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c +index c0f12ed9d..6b043844d 100644 +--- a/src/lib/krb5/rcache/rc_dfl.c ++++ b/src/lib/krb5/rcache/rc_dfl.c +@@ -97,8 +97,7 @@ alive(krb5_int32 mytime, krb5_donot_replay *new1, krb5_deltat t) + { + if (mytime == 0) + return CMP_HOHUM; /* who cares? */ +- /* I hope we don't have to worry about overflow */ +- if (new1->ctime + t < mytime) ++ if (ts_after(mytime, ts_incr(new1->ctime, t))) + return CMP_EXPIRED; + return CMP_HOHUM; + } +diff --git a/src/lib/krb5/rcache/t_replay.c b/src/lib/krb5/rcache/t_replay.c +index db273ec2f..b99cdf1ab 100644 +--- a/src/lib/krb5/rcache/t_replay.c ++++ b/src/lib/krb5/rcache/t_replay.c +@@ -110,7 +110,7 @@ store(krb5_context ctx, char *rcspec, char *client, char *server, char *msg, + krb5_donot_replay rep; + krb5_data d; + +- if (now_timestamp > 0) ++ if (now_timestamp != 0) + krb5_set_debugging_time(ctx, now_timestamp, now_usec); + if ((retval = krb5_rc_resolve_full(ctx, &rc, rcspec))) + goto cleanup; +@@ -221,13 +221,13 @@ main(int argc, char **argv) + msg = (**argv) ? *argv : NULL; + argc--; argv++; + if (!argc) usage(progname); +- timestamp = (krb5_timestamp) atol(*argv); ++ timestamp = (krb5_timestamp) atoll(*argv); + argc--; argv++; + if (!argc) usage(progname); + usec = (krb5_int32) atol(*argv); + argc--; argv++; + if (!argc) usage(progname); +- now_timestamp = (krb5_timestamp) atol(*argv); ++ now_timestamp = (krb5_timestamp) atoll(*argv); + argc--; argv++; + if (!argc) usage(progname); + now_usec = (krb5_int32) atol(*argv); +@@ -249,7 +249,7 @@ main(int argc, char **argv) + rcspec = *argv; + argc--; argv++; + if (!argc) usage(progname); +- now_timestamp = (krb5_timestamp) atol(*argv); ++ now_timestamp = (krb5_timestamp) atoll(*argv); + argc--; argv++; + if (!argc) usage(progname); + now_usec = (krb5_int32) atol(*argv); +diff --git a/src/plugins/kdb/db2/lockout.c b/src/plugins/kdb/db2/lockout.c +index 7d151b55b..3a4f41821 100644 +--- a/src/plugins/kdb/db2/lockout.c ++++ b/src/plugins/kdb/db2/lockout.c +@@ -100,7 +100,7 @@ locked_check_p(krb5_context context, + + /* If the entry was unlocked since the last failure, it's not locked. */ + if (krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time) == 0 && +- entry->last_failed <= unlock_time) ++ !ts_after(entry->last_failed, unlock_time)) + return FALSE; + + if (max_fail == 0 || entry->fail_auth_count < max_fail) +@@ -109,7 +109,7 @@ locked_check_p(krb5_context context, + if (lockout_duration == 0) + return TRUE; /* principal permanently locked */ + +- return (stamp < entry->last_failed + lockout_duration); ++ return ts_after(ts_incr(entry->last_failed, lockout_duration), stamp); + } + + krb5_error_code +@@ -200,13 +200,13 @@ krb5_db2_lockout_audit(krb5_context context, + status == KRB5KRB_AP_ERR_BAD_INTEGRITY)) { + if (krb5_dbe_lookup_last_admin_unlock(context, entry, + &unlock_time) == 0 && +- entry->last_failed <= unlock_time) { ++ !ts_after(entry->last_failed, unlock_time)) { + /* Reset fail_auth_count after administrative unlock. */ + entry->fail_auth_count = 0; + } + + if (failcnt_interval != 0 && +- stamp > entry->last_failed + failcnt_interval) { ++ ts_after(stamp, ts_incr(entry->last_failed, failcnt_interval))) { + /* Reset fail_auth_count after failcnt_interval. */ + entry->fail_auth_count = 0; + } +diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +index 7ba53f959..88a170495 100644 +--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c ++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +@@ -1734,7 +1734,7 @@ getstringtime(krb5_timestamp epochtime) + { + struct tm tme; + char *strtime=NULL; +- time_t posixtime = epochtime; ++ time_t posixtime = ts2tt(epochtime); + + strtime = calloc (50, 1); + if (strtime == NULL) +diff --git a/src/plugins/kdb/ldap/libkdb_ldap/lockout.c b/src/plugins/kdb/ldap/libkdb_ldap/lockout.c +index 0fc56c2fe..1088ecc5a 100644 +--- a/src/plugins/kdb/ldap/libkdb_ldap/lockout.c ++++ b/src/plugins/kdb/ldap/libkdb_ldap/lockout.c +@@ -93,7 +93,7 @@ locked_check_p(krb5_context context, + + /* If the entry was unlocked since the last failure, it's not locked. */ + if (krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time) == 0 && +- entry->last_failed <= unlock_time) ++ !ts_after(entry->last_failed, unlock_time)) + return FALSE; + + if (max_fail == 0 || entry->fail_auth_count < max_fail) +@@ -102,7 +102,7 @@ locked_check_p(krb5_context context, + if (lockout_duration == 0) + return TRUE; /* principal permanently locked */ + +- return (stamp < entry->last_failed + lockout_duration); ++ return ts_after(ts_incr(entry->last_failed, lockout_duration), stamp); + } + + krb5_error_code +@@ -196,14 +196,14 @@ krb5_ldap_lockout_audit(krb5_context context, + status == KRB5KRB_AP_ERR_BAD_INTEGRITY)) { + if (krb5_dbe_lookup_last_admin_unlock(context, entry, + &unlock_time) == 0 && +- entry->last_failed <= unlock_time) { ++ !ts_after(entry->last_failed, unlock_time)) { + /* Reset fail_auth_count after administrative unlock. */ + entry->fail_auth_count = 0; + entry->mask |= KADM5_FAIL_AUTH_COUNT; + } + + if (failcnt_interval != 0 && +- stamp > entry->last_failed + failcnt_interval) { ++ ts_after(stamp, ts_incr(entry->last_failed, failcnt_interval))) { + /* Reset fail_auth_count after failcnt_interval */ + entry->fail_auth_count = 0; + entry->mask |= KADM5_FAIL_AUTH_COUNT; +diff --git a/src/windows/cns/tktlist.c b/src/windows/cns/tktlist.c +index f2805f5cd..26e699fae 100644 +--- a/src/windows/cns/tktlist.c ++++ b/src/windows/cns/tktlist.c +@@ -35,6 +35,8 @@ + #include "cns.h" + #include "tktlist.h" + ++#define ts2tt(t) (time_t)(uint32_t)(t) ++ + /* + * Ticket information for a list line + */ +@@ -167,10 +169,10 @@ ticket_init_list (HWND hwnd) + + ncred++; + strcpy (buf, " "); +- strncat(buf, short_date (c.times.starttime - kwin_get_epoch()), ++ strncat(buf, short_date(ts2tt(c.times.starttime) - kwin_get_epoch()), + sizeof(buf) - 1 - strlen(buf)); + strncat(buf, " ", sizeof(buf) - 1 - strlen(buf)); +- strncat(buf, short_date (c.times.endtime - kwin_get_epoch()), ++ strncat(buf, short_date(ts2tt(c.times.endtime) - kwin_get_epoch()), + sizeof(buf) - 1 - strlen(buf)); + strncat(buf, " ", sizeof(buf) - 1 - strlen(buf)); + +@@ -192,8 +194,8 @@ ticket_init_list (HWND hwnd) + return -1; + + lpinfo->ticket = TRUE; +- lpinfo->issue_time = c.times.starttime - kwin_get_epoch(); +- lpinfo->lifetime = c.times.endtime - c.times.starttime; ++ lpinfo->issue_time = ts2tt(c.times.starttime) - kwin_get_epoch(); ++ lpinfo->lifetime = ts2tt(c.times.endtime) - c.times.starttime; + strcpy(lpinfo->buf, buf); + + rc = ListBox_AddItemData(hwnd, lpinfo); +diff --git a/src/windows/include/leashwin.h b/src/windows/include/leashwin.h +index 9577365a7..325dce2e9 100644 +--- a/src/windows/include/leashwin.h ++++ b/src/windows/include/leashwin.h +@@ -111,9 +111,9 @@ struct TicketList { + TicketList *next; + char *service; + char *encTypes; +- krb5_timestamp issued; +- krb5_timestamp valid_until; +- krb5_timestamp renew_until; ++ time_t issued; ++ time_t valid_until; ++ time_t renew_until; + unsigned long flags; + }; + +@@ -124,9 +124,9 @@ struct TICKETINFO { + char *ccache_name; + TicketList *ticket_list; + int btickets; /* Do we have tickets? */ +- long issued; /* The issue time */ +- long valid_until; /* */ +- long renew_until; /* The Renew time (k5 only) */ ++ time_t issued; /* The issue time */ ++ time_t valid_until; /* */ ++ time_t renew_until; /* The Renew time (k5 only) */ + unsigned long flags; + }; + +diff --git a/src/windows/leash/KrbListTickets.cpp b/src/windows/leash/KrbListTickets.cpp +index beab0ea11..5dd37b05a 100644 +--- a/src/windows/leash/KrbListTickets.cpp ++++ b/src/windows/leash/KrbListTickets.cpp +@@ -92,10 +92,10 @@ etype_string(krb5_enctype enctype) + static void + CredToTicketInfo(krb5_creds KRBv5Credentials, TICKETINFO *ticketinfo) + { +- ticketinfo->issued = KRBv5Credentials.times.starttime; +- ticketinfo->valid_until = KRBv5Credentials.times.endtime; ++ ticketinfo->issued = (DWORD)KRBv5Credentials.times.starttime; ++ ticketinfo->valid_until = (DWORD)KRBv5Credentials.times.endtime; + ticketinfo->renew_until = KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE ? +- KRBv5Credentials.times.renew_till : 0; ++ (DWORD)KRBv5Credentials.times.renew_till : (DWORD)0; + _tzset(); + if ( ticketinfo->valid_until - time(0) <= 0L ) + ticketinfo->btickets = EXPD_TICKETS; +@@ -137,10 +137,10 @@ CredToTicketList(krb5_context ctx, krb5_creds KRBv5Credentials, + functionName = "calloc()"; + goto cleanup; + } +- list->issued = KRBv5Credentials.times.starttime; +- list->valid_until = KRBv5Credentials.times.endtime; ++ list->issued = (DWORD)KRBv5Credentials.times.starttime; ++ list->valid_until = (DWORD)KRBv5Credentials.times.endtime; + if (KRBv5Credentials.ticket_flags & TKT_FLG_RENEWABLE) +- list->renew_until = KRBv5Credentials.times.renew_till; ++ list->renew_until = (DWORD)KRBv5Credentials.times.renew_till; + else + list->renew_until = 0; + +diff --git a/src/windows/leash/LeashView.cpp b/src/windows/leash/LeashView.cpp +index ef2a5a3e0..253ae3f06 100644 +--- a/src/windows/leash/LeashView.cpp ++++ b/src/windows/leash/LeashView.cpp +@@ -229,22 +229,22 @@ static HFONT CreateBoldItalicFont(HFONT font) + + bool change_icon_size = true; + +-void krb5TimestampToFileTime(krb5_timestamp t, LPFILETIME pft) ++void TimestampToFileTime(time_t t, LPFILETIME pft) + { + // Note that LONGLONG is a 64-bit value +- LONGLONG ll; ++ ULONGLONG ll; + +- ll = Int32x32To64(t, 10000000) + 116444736000000000; ++ ll = UInt32x32To64((DWORD)t, 10000000) + 116444736000000000; + pft->dwLowDateTime = (DWORD)ll; + pft->dwHighDateTime = ll >> 32; + } + + // allocate outstr +-void krb5TimestampToLocalizedString(krb5_timestamp t, LPTSTR *outStr) ++void TimestampToLocalizedString(time_t t, LPTSTR *outStr) + { + FILETIME ft, lft; + SYSTEMTIME st; +- krb5TimestampToFileTime(t, &ft); ++ TimestampToFileTime(t, &ft); + FileTimeToLocalFileTime(&ft, &lft); + FileTimeToSystemTime(&lft, &st); + TCHAR timeFormat[80]; // 80 is max required for LOCALE_STIMEFORMAT +@@ -1125,9 +1125,9 @@ void CLeashView::AddDisplayItem(CListCtrl &list, + CCacheDisplayData *elem, + int iItem, + char *principal, +- long issued, +- long valid_until, +- long renew_until, ++ time_t issued, ++ time_t valid_until, ++ time_t renew_until, + char *encTypes, + unsigned long flags, + char *ccache_name) +@@ -1145,7 +1145,7 @@ void CLeashView::AddDisplayItem(CListCtrl &list, + if (issued == 0) { + list.SetItemText(iItem, iSubItem++, "Unknown"); + } else { +- krb5TimestampToLocalizedString(issued, &localTimeStr); ++ TimestampToLocalizedString(issued, &localTimeStr); + list.SetItemText(iItem, iSubItem++, localTimeStr); + } + } +@@ -1155,7 +1155,7 @@ void CLeashView::AddDisplayItem(CListCtrl &list, + } else if (valid_until < now) { + list.SetItemText(iItem, iSubItem++, "Expired"); + } else if (renew_until) { +- krb5TimestampToLocalizedString(renew_until, &localTimeStr); ++ TimestampToLocalizedString(renew_until, &localTimeStr); + DurationToString(renew_until - now, &durationStr); + if (localTimeStr && durationStr) { + _snprintf(tempStr, MAX_DURATION_STR, "%s %s", localTimeStr, durationStr); +@@ -1172,7 +1172,7 @@ void CLeashView::AddDisplayItem(CListCtrl &list, + } else if (valid_until < now) { + list.SetItemText(iItem, iSubItem++, "Expired"); + } else { +- krb5TimestampToLocalizedString(valid_until, &localTimeStr); ++ TimestampToLocalizedString(valid_until, &localTimeStr); + DurationToString(valid_until - now, &durationStr); + if (localTimeStr && durationStr) { + _snprintf(tempStr, MAX_DURATION_STR, "%s %s", localTimeStr, durationStr); +diff --git a/src/windows/leashdll/lshfunc.c b/src/windows/leashdll/lshfunc.c +index 0f76cc334..8dafb7bed 100644 +--- a/src/windows/leashdll/lshfunc.c ++++ b/src/windows/leashdll/lshfunc.c +@@ -2898,7 +2898,7 @@ static BOOL cc_have_tickets(krb5_context ctx, krb5_ccache cache) + _tzset(); + while (!(code = pkrb5_cc_next_cred(ctx, cache, &cur, &creds))) { + if ((!pkrb5_is_config_principal(ctx, creds.server)) && +- (creds.times.endtime - time(0) > 0)) ++ ((time_t)(DWORD)creds.times.endtime - time(0) > 0)) + have_tickets = TRUE; + + pkrb5_free_cred_contents(ctx, &creds); +diff --git a/src/windows/ms2mit/ms2mit.c b/src/windows/ms2mit/ms2mit.c +index c3325034a..2b4373cc1 100644 +--- a/src/windows/ms2mit/ms2mit.c ++++ b/src/windows/ms2mit/ms2mit.c +@@ -74,7 +74,7 @@ cc_has_tickets(krb5_context kcontext, krb5_ccache ccache, int *has_tickets) + break; + + if (!krb5_is_config_principal(kcontext, creds.server) && +- creds.times.endtime > now) ++ ts_after(creds.times.endtime, now)) + *has_tickets = 1; + + krb5_free_cred_contents(kcontext, &creds); diff --git a/SOURCES/Prevent-KDC-unset-status-assertion-failures.patch b/SOURCES/Prevent-KDC-unset-status-assertion-failures.patch new file mode 100644 index 0000000..084f55e --- /dev/null +++ b/SOURCES/Prevent-KDC-unset-status-assertion-failures.patch @@ -0,0 +1,110 @@ +From 3b2376b47a9f1fc7dfd138d4ecc70e5d8897dc2b Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Thu, 13 Jul 2017 12:14:20 -0400 +Subject: [PATCH] Prevent KDC unset status assertion failures + +Assign status values if S4U2Self padata fails to decode, if an +S4U2Proxy request uses invalid KDC options, or if an S4U2Proxy request +uses an evidence ticket which does not match the canonicalized request +server principal name. Reported by Samuel Cabrero. + +If a status value is not assigned during KDC processing, default to +"UNKNOWN_REASON" rather than failing an assertion. This change will +prevent future denial of service bugs due to similar mistakes, and +will allow us to omit assigning status values for unlikely errors such +as small memory allocation failures. + +CVE-2017-11368: + +In MIT krb5 1.7 and later, an authenticated attacker can cause an +assertion failure in krb5kdc by sending an invalid S4U2Self or +S4U2Proxy request. + + CVSSv3 Vector: AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H/E:H/RL:O/RC:C + +ticket: 8599 (new) +target_version: 1.15-next +target_version: 1.14-next +tags: pullup + +(cherry picked from commit ffb35baac6981f9e8914f8f3bffd37f284b85970) +Signed-off-by: Robbie Harwood +--- + src/kdc/do_as_req.c | 4 ++-- + src/kdc/do_tgs_req.c | 3 ++- + src/kdc/kdc_util.c | 10 ++++++++-- + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c +index 241b05b40..f5cf8ad89 100644 +--- a/src/kdc/do_as_req.c ++++ b/src/kdc/do_as_req.c +@@ -372,8 +372,8 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode) + did_log = 1; + + egress: +- if (errcode != 0) +- assert (state->status != 0); ++ if (errcode != 0 && state->status == NULL) ++ state->status = "UNKNOWN_REASON"; + + au_state->status = state->status; + au_state->reply = &state->reply; +diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c +index 4c722a4a3..0009a9319 100644 +--- a/src/kdc/do_tgs_req.c ++++ b/src/kdc/do_tgs_req.c +@@ -829,7 +829,8 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, + free(reply.enc_part.ciphertext.data); + + cleanup: +- assert(status != NULL); ++ if (status == NULL) ++ status = "UNKNOWN_REASON"; + if (reply_key) + krb5_free_keyblock(kdc_context, reply_key); + if (errcode) +diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c +index 8cbdf2c5b..5455e2a67 100644 +--- a/src/kdc/kdc_util.c ++++ b/src/kdc/kdc_util.c +@@ -1213,8 +1213,10 @@ kdc_process_for_user(kdc_realm_t *kdc_active_realm, + req_data.data = (char *)pa_data->contents; + + code = decode_krb5_pa_for_user(&req_data, &for_user); +- if (code) ++ if (code) { ++ *status = "DECODE_PA_FOR_USER"; + return code; ++ } + + code = verify_for_user_checksum(kdc_context, tgs_session, for_user); + if (code) { +@@ -1313,8 +1315,10 @@ kdc_process_s4u_x509_user(krb5_context context, + req_data.data = (char *)pa_data->contents; + + code = decode_krb5_pa_s4u_x509_user(&req_data, s4u_x509_user); +- if (code) ++ if (code) { ++ *status = "DECODE_PA_S4U_X509_USER"; + return code; ++ } + + code = verify_s4u_x509_user_checksum(context, + tgs_subkey ? tgs_subkey : +@@ -1617,6 +1621,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, + * that is validated previously in validate_tgs_request(). + */ + if (request->kdc_options & (NON_TGT_OPTION | KDC_OPT_ENC_TKT_IN_SKEY)) { ++ *status = "INVALID_S4U2PROXY_OPTIONS"; + return KRB5KDC_ERR_BADOPTION; + } + +@@ -1624,6 +1629,7 @@ kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, + if (!krb5_principal_compare(kdc_context, + server->princ, /* after canon */ + server_princ)) { ++ *status = "EVIDENCE_TICKET_MISMATCH"; + return KRB5KDC_ERR_SERVER_NOMATCH; + } + diff --git a/SOURCES/Remove-incomplete-PKINIT-OCSP-support.patch b/SOURCES/Remove-incomplete-PKINIT-OCSP-support.patch new file mode 100644 index 0000000..94315ea --- /dev/null +++ b/SOURCES/Remove-incomplete-PKINIT-OCSP-support.patch @@ -0,0 +1,135 @@ +From 9ff3ed399f9a5bb0c6101a986798d80ecc7a1b92 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Mon, 31 Jul 2017 16:03:41 -0400 +Subject: [PATCH] Remove incomplete PKINIT OCSP support + +pkinit_kdc_ocsp is non-functional in the PKINIT OpenSSL crypto +implementation, so remove most traces of it, including its man page +entry. If it is present in kdc.conf, error out of PKINIT +initialization instead of silently ignoring the realm entirely. + +ticket: 8603 (new) +(cherry picked from commit 3ff426b9048a8024e5c175256c63cd0ad0572320) +Signed-off-by: Robbie Harwood +--- + doc/admin/conf_files/kdc_conf.rst | 3 --- + src/man/kdc.conf.man | 3 --- + src/plugins/preauth/pkinit/pkinit.h | 2 +- + src/plugins/preauth/pkinit/pkinit_identity.c | 11 ----------- + src/plugins/preauth/pkinit/pkinit_srv.c | 12 ++++++++++-- + 5 files changed, 11 insertions(+), 20 deletions(-) + +diff --git a/doc/admin/conf_files/kdc_conf.rst b/doc/admin/conf_files/kdc_conf.rst +index 13077ecf4..a4b2a5432 100644 +--- a/doc/admin/conf_files/kdc_conf.rst ++++ b/doc/admin/conf_files/kdc_conf.rst +@@ -765,9 +765,6 @@ For information about the syntax of some of these options, see + pkinit is used to authenticate. This option may be specified + multiple times. (New in release 1.14.) + +-**pkinit_kdc_ocsp** +- Specifies the location of the KDC's OCSP. +- + **pkinit_pool** + Specifies the location of intermediate certificates which may be + used by the KDC to complete the trust chain between a client's +diff --git a/src/man/kdc.conf.man b/src/man/kdc.conf.man +index 10b333c38..166e68f9a 100644 +--- a/src/man/kdc.conf.man ++++ b/src/man/kdc.conf.man +@@ -886,9 +886,6 @@ Specifies an authentication indicator to include in the ticket if + pkinit is used to authenticate. This option may be specified + multiple times. (New in release 1.14.) + .TP +-.B \fBpkinit_kdc_ocsp\fP +-Specifies the location of the KDC\(aqs OCSP. +-.TP + .B \fBpkinit_pool\fP + Specifies the location of intermediate certificates which may be + used by the KDC to complete the trust chain between a client\(aqs +diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h +index 876db94c3..a49f3078e 100644 +--- a/src/plugins/preauth/pkinit/pkinit.h ++++ b/src/plugins/preauth/pkinit/pkinit.h +@@ -73,6 +73,7 @@ + #define KRB5_CONF_PKINIT_IDENTITIES "pkinit_identities" + #define KRB5_CONF_PKINIT_IDENTITY "pkinit_identity" + #define KRB5_CONF_PKINIT_KDC_HOSTNAME "pkinit_kdc_hostname" ++/* pkinit_kdc_ocsp has been removed */ + #define KRB5_CONF_PKINIT_KDC_OCSP "pkinit_kdc_ocsp" + #define KRB5_CONF_PKINIT_POOL "pkinit_pool" + #define KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING "pkinit_require_crl_checking" +@@ -173,7 +174,6 @@ typedef struct _pkinit_identity_opts { + char **anchors; + char **intermediates; + char **crls; +- char *ocsp; + int idtype; + char *cert_filename; + char *key_filename; +diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c +index 177a2cad8..a897efa25 100644 +--- a/src/plugins/preauth/pkinit/pkinit_identity.c ++++ b/src/plugins/preauth/pkinit/pkinit_identity.c +@@ -125,7 +125,6 @@ pkinit_init_identity_opts(pkinit_identity_opts **idopts) + opts->anchors = NULL; + opts->intermediates = NULL; + opts->crls = NULL; +- opts->ocsp = NULL; + + opts->cert_filename = NULL; + opts->key_filename = NULL; +@@ -174,12 +173,6 @@ pkinit_dup_identity_opts(pkinit_identity_opts *src_opts, + if (retval) + goto cleanup; + +- if (src_opts->ocsp != NULL) { +- newopts->ocsp = strdup(src_opts->ocsp); +- if (newopts->ocsp == NULL) +- goto cleanup; +- } +- + if (src_opts->cert_filename != NULL) { + newopts->cert_filename = strdup(src_opts->cert_filename); + if (newopts->cert_filename == NULL) +@@ -674,10 +667,6 @@ pkinit_identity_prompt(krb5_context context, + if (retval) + goto errout; + } +- if (idopts->ocsp != NULL) { +- retval = ENOTSUP; +- goto errout; +- } + + errout: + return retval; +diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c +index 731d14eb8..32ca122f2 100644 +--- a/src/plugins/preauth/pkinit/pkinit_srv.c ++++ b/src/plugins/preauth/pkinit/pkinit_srv.c +@@ -1252,7 +1252,7 @@ static krb5_error_code + pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx) + { + krb5_error_code retval; +- char *eku_string = NULL; ++ char *eku_string = NULL, *ocsp_check = NULL; + + pkiDebug("%s: entered for realm %s\n", __FUNCTION__, plgctx->realmname); + retval = pkinit_kdcdefault_string(context, plgctx->realmname, +@@ -1287,7 +1287,15 @@ pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx) + + pkinit_kdcdefault_string(context, plgctx->realmname, + KRB5_CONF_PKINIT_KDC_OCSP, +- &plgctx->idopts->ocsp); ++ &ocsp_check); ++ if (ocsp_check != NULL) { ++ free(ocsp_check); ++ retval = ENOTSUP; ++ krb5_set_error_message(context, retval, ++ _("OCSP is not supported: (realm: %s)"), ++ plgctx->realmname); ++ goto errout; ++ } + + pkinit_kdcdefault_integer(context, plgctx->realmname, + KRB5_CONF_PKINIT_DH_MIN_BITS, diff --git a/SOURCES/Use-krb5_timestamp-where-appropriate.patch b/SOURCES/Use-krb5_timestamp-where-appropriate.patch new file mode 100644 index 0000000..084c698 --- /dev/null +++ b/SOURCES/Use-krb5_timestamp-where-appropriate.patch @@ -0,0 +1,328 @@ +From f181bf6ee4ff66489895a8c543521cbec253d1f9 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Wed, 17 May 2017 15:14:15 -0400 +Subject: [PATCH] Use krb5_timestamp where appropriate + +Where krb5_int32 is used to hold the number of seconds since the +epoch, use krb5_timestamp instead. + +(cherry picked from commit ae25f6ec5558140a546db34fea389412d81c0631) +Signed-off-by: Robbie Harwood +--- + src/clients/klist/klist.c | 2 +- + src/include/k5-int.h | 2 +- + src/kadmin/server/misc.c | 2 +- + src/kdc/dispatch.c | 4 ++-- + src/lib/kadm5/srv/server_acl.c | 2 +- + src/lib/kadm5/srv/server_kdb.c | 2 +- + src/lib/kadm5/srv/svr_principal.c | 10 +++++----- + src/lib/krb5/krb/gen_save_subkey.c | 3 ++- + src/lib/krb5/krb/get_in_tkt.c | 2 +- + src/lib/krb5/krb/init_ctx.c | 3 ++- + src/lib/krb5/os/c_ustime.c | 7 +++++-- + src/lib/krb5/os/toffset.c | 3 ++- + src/lib/krb5/os/trace.c | 3 ++- + src/lib/krb5/os/ustime.c | 3 ++- + src/lib/krb5/rcache/rc_dfl.c | 10 +++++----- + src/tests/create/kdb5_mkdums.c | 2 +- + 16 files changed, 34 insertions(+), 26 deletions(-) + +diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c +index ffeecc394..4334415be 100644 +--- a/src/clients/klist/klist.c ++++ b/src/clients/klist/klist.c +@@ -56,7 +56,7 @@ int show_adtype = 0, show_all = 0, list_all = 0, use_client_keytab = 0; + int show_config = 0; + char *defname; + char *progname; +-krb5_int32 now; ++krb5_timestamp now; + unsigned int timestamp_width; + + krb5_context kcontext; +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index 82ee20760..ed9c7bf75 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -721,7 +721,7 @@ krb5_error_code krb5int_c_copy_keyblock_contents(krb5_context context, + const krb5_keyblock *from, + krb5_keyblock *to); + +-krb5_error_code krb5_crypto_us_timeofday(krb5_int32 *, krb5_int32 *); ++krb5_error_code krb5_crypto_us_timeofday(krb5_timestamp *, krb5_int32 *); + + /* + * End "los-proto.h" +diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c +index a75b65a26..ba672d714 100644 +--- a/src/kadmin/server/misc.c ++++ b/src/kadmin/server/misc.c +@@ -159,7 +159,7 @@ kadm5_ret_t + check_min_life(void *server_handle, krb5_principal principal, + char *msg_ret, unsigned int msg_len) + { +- krb5_int32 now; ++ krb5_timestamp now; + kadm5_ret_t ret; + kadm5_policy_ent_rec pol; + kadm5_principal_ent_rec princ; +diff --git a/src/kdc/dispatch.c b/src/kdc/dispatch.c +index 16a35d2be..4ecc23481 100644 +--- a/src/kdc/dispatch.c ++++ b/src/kdc/dispatch.c +@@ -94,8 +94,8 @@ static void + reseed_random(krb5_context kdc_err_context) + { + krb5_error_code retval; +- krb5_int32 now, now_usec; +- krb5_int32 usec_difference; ++ krb5_timestamp now; ++ krb5_int32 now_usec, usec_difference; + krb5_data data; + + retval = krb5_crypto_us_timeofday(&now, &now_usec); +diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c +index 656dddff5..c2cf69169 100644 +--- a/src/lib/kadm5/srv/server_acl.c ++++ b/src/lib/kadm5/srv/server_acl.c +@@ -375,7 +375,7 @@ kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp) + restriction_t *rp; + { + krb5_error_code code; +- krb5_int32 now; ++ krb5_timestamp now; + + DPRINT(DEBUG_CALLS, acl_debug_level, + ("* kadm5int_acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n", +diff --git a/src/lib/kadm5/srv/server_kdb.c b/src/lib/kadm5/srv/server_kdb.c +index 612553ba3..f4b8aef2b 100644 +--- a/src/lib/kadm5/srv/server_kdb.c ++++ b/src/lib/kadm5/srv/server_kdb.c +@@ -365,7 +365,7 @@ kdb_put_entry(kadm5_server_handle_t handle, + krb5_db_entry *kdb, osa_princ_ent_rec *adb) + { + krb5_error_code ret; +- krb5_int32 now; ++ krb5_timestamp now; + XDR xdrs; + krb5_tl_data tl_data; + +diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c +index f4a9a2ad2..0d4f0a632 100644 +--- a/src/lib/kadm5/srv/svr_principal.c ++++ b/src/lib/kadm5/srv/svr_principal.c +@@ -296,7 +296,7 @@ kadm5_create_principal_3(void *server_handle, + osa_princ_ent_rec adb; + kadm5_policy_ent_rec polent; + krb5_boolean have_polent = FALSE; +- krb5_int32 now; ++ krb5_timestamp now; + krb5_tl_data *tl_data_tail; + unsigned int ret; + kadm5_server_handle_t handle = server_handle; +@@ -1322,7 +1322,7 @@ kadm5_chpass_principal_3(void *server_handle, + int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, + char *password) + { +- krb5_int32 now; ++ krb5_timestamp now; + kadm5_policy_ent_rec pol; + osa_princ_ent_rec adb; + krb5_db_entry *kdb; +@@ -1544,7 +1544,7 @@ kadm5_randkey_principal_3(void *server_handle, + { + krb5_db_entry *kdb; + osa_princ_ent_rec adb; +- krb5_int32 now; ++ krb5_timestamp now; + kadm5_policy_ent_rec pol; + int ret, last_pwd, n_new_keys; + krb5_boolean have_pol = FALSE; +@@ -1686,7 +1686,7 @@ kadm5_setv4key_principal(void *server_handle, + { + krb5_db_entry *kdb; + osa_princ_ent_rec adb; +- krb5_int32 now; ++ krb5_timestamp now; + kadm5_policy_ent_rec pol; + krb5_keysalt keysalt; + int i, kvno, ret; +@@ -1888,7 +1888,7 @@ kadm5_setkey_principal_4(void *server_handle, krb5_principal principal, + { + krb5_db_entry *kdb; + osa_princ_ent_rec adb; +- krb5_int32 now; ++ krb5_timestamp now; + kadm5_policy_ent_rec pol; + krb5_key_data *new_key_data = NULL; + int i, j, ret, n_new_key_data = 0; +diff --git a/src/lib/krb5/krb/gen_save_subkey.c b/src/lib/krb5/krb/gen_save_subkey.c +index 61f36aa36..bc2c46d30 100644 +--- a/src/lib/krb5/krb/gen_save_subkey.c ++++ b/src/lib/krb5/krb/gen_save_subkey.c +@@ -38,7 +38,8 @@ k5_generate_and_save_subkey(krb5_context context, + to guarantee randomness, but to make it less likely that multiple + sessions could pick the same subkey. */ + struct { +- krb5_int32 sec, usec; ++ krb5_timestamp sec; ++ krb5_int32 usec; + } rnd_data; + krb5_data d; + krb5_error_code retval; +diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c +index 40aba1905..7178bd87b 100644 +--- a/src/lib/krb5/krb/get_in_tkt.c ++++ b/src/lib/krb5/krb/get_in_tkt.c +@@ -1788,7 +1788,7 @@ k5_populate_gic_opt(krb5_context context, krb5_get_init_creds_opt **out, + krb5_creds *creds) + { + int i; +- krb5_int32 starttime; ++ krb5_timestamp starttime; + krb5_deltat lifetime; + krb5_get_init_creds_opt *opt; + krb5_error_code retval; +diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c +index cf226fdba..4246c5dd2 100644 +--- a/src/lib/krb5/krb/init_ctx.c ++++ b/src/lib/krb5/krb/init_ctx.c +@@ -139,7 +139,8 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags, + krb5_context ctx = 0; + krb5_error_code retval; + struct { +- krb5_int32 now, now_usec; ++ krb5_timestamp now; ++ krb5_int32 now_usec; + long pid; + } seed_data; + krb5_data seed; +diff --git a/src/lib/krb5/os/c_ustime.c b/src/lib/krb5/os/c_ustime.c +index 68fb381f4..f69f2ea4c 100644 +--- a/src/lib/krb5/os/c_ustime.c ++++ b/src/lib/krb5/os/c_ustime.c +@@ -29,7 +29,10 @@ + + k5_mutex_t krb5int_us_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER; + +-struct time_now { krb5_int32 sec, usec; }; ++struct time_now { ++ krb5_timestamp sec; ++ krb5_int32 usec; ++}; + + #if defined(_WIN32) + +@@ -73,7 +76,7 @@ get_time_now(struct time_now *n) + static struct time_now last_time; + + krb5_error_code +-krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds) ++krb5_crypto_us_timeofday(krb5_timestamp *seconds, krb5_int32 *microseconds) + { + struct time_now now; + krb5_error_code err; +diff --git a/src/lib/krb5/os/toffset.c b/src/lib/krb5/os/toffset.c +index 37bc69f49..4bbcdde52 100644 +--- a/src/lib/krb5/os/toffset.c ++++ b/src/lib/krb5/os/toffset.c +@@ -40,7 +40,8 @@ krb5_error_code KRB5_CALLCONV + krb5_set_real_time(krb5_context context, krb5_timestamp seconds, krb5_int32 microseconds) + { + krb5_os_context os_ctx = &context->os_context; +- krb5_int32 sec, usec; ++ krb5_timestamp sec; ++ krb5_int32 usec; + krb5_error_code retval; + + retval = krb5_crypto_us_timeofday(&sec, &usec); +diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c +index 74c315c90..8750b7650 100644 +--- a/src/lib/krb5/os/trace.c ++++ b/src/lib/krb5/os/trace.c +@@ -340,7 +340,8 @@ krb5int_trace(krb5_context context, const char *fmt, ...) + va_list ap; + krb5_trace_info info; + char *str = NULL, *msg = NULL; +- krb5_int32 sec, usec; ++ krb5_timestamp sec; ++ krb5_int32 usec; + + if (context == NULL || context->trace_callback == NULL) + return; +diff --git a/src/lib/krb5/os/ustime.c b/src/lib/krb5/os/ustime.c +index 1c1b571eb..a80fdf68c 100644 +--- a/src/lib/krb5/os/ustime.c ++++ b/src/lib/krb5/os/ustime.c +@@ -40,7 +40,8 @@ krb5_error_code + k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec, + krb5_timestamp *time_out, krb5_int32 *usec_out) + { +- krb5_int32 sec, usec; ++ krb5_timestamp sec; ++ krb5_int32 usec; + krb5_error_code retval; + + retval = krb5_crypto_us_timeofday(&sec, &usec); +diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c +index 6b043844d..41ebf94da 100644 +--- a/src/lib/krb5/rcache/rc_dfl.c ++++ b/src/lib/krb5/rcache/rc_dfl.c +@@ -93,7 +93,7 @@ cmp(krb5_donot_replay *old, krb5_donot_replay *new1, krb5_deltat t) + } + + static int +-alive(krb5_int32 mytime, krb5_donot_replay *new1, krb5_deltat t) ++alive(krb5_timestamp mytime, krb5_donot_replay *new1, krb5_deltat t) + { + if (mytime == 0) + return CMP_HOHUM; /* who cares? */ +@@ -129,7 +129,7 @@ struct authlist + + static int + rc_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep, +- krb5_int32 now, krb5_boolean fromfile) ++ krb5_timestamp now, krb5_boolean fromfile) + { + struct dfl_data *t = (struct dfl_data *)id->data; + unsigned int rephash; +@@ -536,7 +536,7 @@ krb5_rc_dfl_recover_locked(krb5_context context, krb5_rcache id) + krb5_error_code retval; + long max_size; + int expired_entries = 0; +- krb5_int32 now; ++ krb5_timestamp now; + + if ((retval = krb5_rc_io_open(context, &t->d, t->name))) { + return retval; +@@ -706,7 +706,7 @@ krb5_rc_dfl_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep) + { + krb5_error_code ret; + struct dfl_data *t; +- krb5_int32 now; ++ krb5_timestamp now; + + ret = krb5_timeofday(context, &now); + if (ret) +@@ -762,7 +762,7 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id) + struct authlist **qt; + struct authlist *r; + struct authlist *rt; +- krb5_int32 now; ++ krb5_timestamp now; + + if (krb5_timestamp(context, &now)) + now = 0; +diff --git a/src/tests/create/kdb5_mkdums.c b/src/tests/create/kdb5_mkdums.c +index 622f549f9..7c0666601 100644 +--- a/src/tests/create/kdb5_mkdums.c ++++ b/src/tests/create/kdb5_mkdums.c +@@ -247,7 +247,7 @@ add_princ(context, str_newprinc) + + { + /* Add mod princ to db entry */ +- krb5_int32 now; ++ krb5_timestamp now; + + retval = krb5_timeofday(context, &now); + if (retval) { diff --git a/SOURCES/Use-the-canonical-client-principal-name-for-OTP.patch b/SOURCES/Use-the-canonical-client-principal-name-for-OTP.patch index 2089450..e77b58a 100644 --- a/SOURCES/Use-the-canonical-client-principal-name-for-OTP.patch +++ b/SOURCES/Use-the-canonical-client-principal-name-for-OTP.patch @@ -1,4 +1,4 @@ -From 7c922602fe8fec44c55558daa32061cea86355cb Mon Sep 17 00:00:00 2001 +From 685698f8d33810ce085da4d75d1d8febe5323fd3 Mon Sep 17 00:00:00 2001 From: Matt Rogers Date: Wed, 5 Apr 2017 16:48:55 -0400 Subject: [PATCH] Use the canonical client principal name for OTP @@ -9,6 +9,7 @@ callback) instead of the request client principal. ticket: 8571 (new) (cherry picked from commit 6411398e35e343cdc4d2d103b079c4d3b9031f7e) +Signed-off-by: Robbie Harwood --- src/plugins/preauth/otp/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SOURCES/krb5-1.11-kpasswdtest.patch b/SOURCES/krb5-1.11-kpasswdtest.patch index 4657926..d58987e 100644 --- a/SOURCES/krb5-1.11-kpasswdtest.patch +++ b/SOURCES/krb5-1.11-kpasswdtest.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Fri, 22 Apr 2016 10:03:40 -0400 Subject: [PATCH] krb5-1.11-kpasswdtest.patch +Signed-off-by: Robbie Harwood --- src/kadmin/testing/proto/krb5.conf.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/SOURCES/krb5-1.11-run_user_0.patch b/SOURCES/krb5-1.11-run_user_0.patch index 734341c..3093df6 100644 --- a/SOURCES/krb5-1.11-run_user_0.patch +++ b/SOURCES/krb5-1.11-run_user_0.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Fri, 22 Apr 2016 10:03:22 -0400 Subject: [PATCH] krb5-1.11-run_user_0.patch +Signed-off-by: Robbie Harwood --- src/lib/krb5/ccache/cc_dir.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/SOURCES/krb5-1.12-api.patch b/SOURCES/krb5-1.12-api.patch index ae261d5..e040029 100644 --- a/SOURCES/krb5-1.12-api.patch +++ b/SOURCES/krb5-1.12-api.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Fri, 22 Apr 2016 09:59:22 -0400 Subject: [PATCH] krb5-1.12-api.patch +Signed-off-by: Robbie Harwood --- src/lib/krb5/krb/princ_comp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/SOURCES/krb5-1.12-ksu-path.patch b/SOURCES/krb5-1.12-ksu-path.patch index 7127916..cc4a074 100644 --- a/SOURCES/krb5-1.12-ksu-path.patch +++ b/SOURCES/krb5-1.12-ksu-path.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Fri, 22 Apr 2016 09:57:25 -0400 Subject: [PATCH] krb5-1.12-ksu-path.patch +Signed-off-by: Robbie Harwood --- src/clients/ksu/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SOURCES/krb5-1.12-ktany.patch b/SOURCES/krb5-1.12-ktany.patch index a518ebf..bae76e2 100644 --- a/SOURCES/krb5-1.12-ktany.patch +++ b/SOURCES/krb5-1.12-ktany.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Fri, 22 Apr 2016 09:58:00 -0400 Subject: [PATCH] krb5-1.12-ktany.patch +Signed-off-by: Robbie Harwood --- src/lib/krb5/keytab/Makefile.in | 3 + src/lib/krb5/keytab/kt_any.c | 292 ++++++++++++++++++++++++++++++++++++++++ diff --git a/SOURCES/krb5-1.12.1-pam.patch b/SOURCES/krb5-1.12.1-pam.patch index 87eeec9..7b8d6f5 100644 --- a/SOURCES/krb5-1.12.1-pam.patch +++ b/SOURCES/krb5-1.12.1-pam.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Mon, 18 Apr 2016 15:57:38 -0400 Subject: [PATCH] krb5-1.12.1-pam.patch +Signed-off-by: Robbie Harwood --- src/aclocal.m4 | 67 ++++++++ src/clients/ksu/Makefile.in | 8 +- diff --git a/SOURCES/krb5-1.13-dirsrv-accountlock.patch b/SOURCES/krb5-1.13-dirsrv-accountlock.patch index 1c7182a..268c859 100644 --- a/SOURCES/krb5-1.13-dirsrv-accountlock.patch +++ b/SOURCES/krb5-1.13-dirsrv-accountlock.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Fri, 22 Apr 2016 10:01:15 -0400 Subject: [PATCH] krb5-1.13-dirsrv-accountlock.patch +Signed-off-by: Robbie Harwood --- src/aclocal.m4 | 9 +++++++++ src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c | 17 +++++++++++++++++ diff --git a/SOURCES/krb5-1.15-beta1-buildconf.patch b/SOURCES/krb5-1.15-beta1-buildconf.patch index 958cfdf..71e122d 100644 --- a/SOURCES/krb5-1.15-beta1-buildconf.patch +++ b/SOURCES/krb5-1.15-beta1-buildconf.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Wed, 4 Jan 2017 13:18:18 -0500 Subject: [PATCH] krb5-1.15-beta1-buildconf.patch +Signed-off-by: Robbie Harwood --- src/build-tools/krb5-config.in | 7 +++++++ src/config/pre.in | 2 +- diff --git a/SOURCES/krb5-1.15-beta1-selinux-label.patch b/SOURCES/krb5-1.15-beta1-selinux-label.patch index 0e79ce9..0cc22e8 100644 --- a/SOURCES/krb5-1.15-beta1-selinux-label.patch +++ b/SOURCES/krb5-1.15-beta1-selinux-label.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Wed, 4 Jan 2017 13:17:28 -0500 Subject: [PATCH] krb5-1.15-beta1-selinux-label.patch +Signed-off-by: Robbie Harwood --- src/aclocal.m4 | 49 +++ src/build-tools/krb5-config.in | 3 +- diff --git a/SOURCES/krb5-1.3.1-dns.patch b/SOURCES/krb5-1.3.1-dns.patch index 7f2cfdf..761722f 100644 --- a/SOURCES/krb5-1.3.1-dns.patch +++ b/SOURCES/krb5-1.3.1-dns.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Fri, 22 Apr 2016 09:59:05 -0400 Subject: [PATCH] krb5-1.3.1-dns.patch +Signed-off-by: Robbie Harwood --- src/aclocal.m4 | 1 + 1 file changed, 1 insertion(+) diff --git a/SOURCES/krb5-1.9-debuginfo.patch b/SOURCES/krb5-1.9-debuginfo.patch index c9a6499..e74a6a9 100644 --- a/SOURCES/krb5-1.9-debuginfo.patch +++ b/SOURCES/krb5-1.9-debuginfo.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Fri, 22 Apr 2016 10:02:40 -0400 Subject: [PATCH] krb5-1.9-debuginfo.patch +Signed-off-by: Robbie Harwood --- src/kadmin/cli/Makefile.in | 5 +++++ src/plugins/kdb/ldap/ldap_util/Makefile.in | 2 +- diff --git a/SOURCES/krb5-kadm5clntmit_libsoname_version_downgrade.patch b/SOURCES/krb5-kadm5clntmit_libsoname_version_downgrade.patch deleted file mode 100644 index c3a7290..0000000 --- a/SOURCES/krb5-kadm5clntmit_libsoname_version_downgrade.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 6fbda5af22095ed1b8ca690bc8269cad04e25034 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood -Date: Fri, 22 Apr 2016 10:03:56 -0400 -Subject: [PATCH] krb5-kadm5clntmit_libsoname_version_downgrade.patch - -[rharwood@redhat.com: Adjust for 1.15] ---- - src/lib/kadm5/clnt/Makefile.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib/kadm5/clnt/Makefile.in b/src/lib/kadm5/clnt/Makefile.in -index a180e85cd..b9aa7aa49 100644 ---- a/src/lib/kadm5/clnt/Makefile.in -+++ b/src/lib/kadm5/clnt/Makefile.in -@@ -3,7 +3,7 @@ BUILDTOP=$(REL)..$(S)..$(S).. - LOCALINCLUDES = -I$(BUILDTOP)/include/kadm5 - - LIBBASE=kadm5clnt_mit --LIBMAJOR=11 -+LIBMAJOR=8 - LIBMINOR=0 - STOBJLISTS=../OBJS.ST OBJS.ST - SHLIB_EXPDEPS=\ diff --git a/SOURCES/krb5-kvno-230379.patch b/SOURCES/krb5-kvno-230379.patch index 0e7c5d5..2005ab9 100644 --- a/SOURCES/krb5-kvno-230379.patch +++ b/SOURCES/krb5-kvno-230379.patch @@ -3,6 +3,7 @@ From: Robbie Harwood Date: Fri, 22 Apr 2016 10:03:07 -0400 Subject: [PATCH] krb5-kvno-230379.patch +Signed-off-by: Robbie Harwood --- src/kadmin/ktutil/ktutil.c | 5 +++-- src/lib/krb5/keytab/kt_file.c | 2 +- diff --git a/SPECS/krb5.spec b/SPECS/krb5.spec index 47b8fe9..e3a5ee2 100644 --- a/SPECS/krb5.spec +++ b/SPECS/krb5.spec @@ -7,13 +7,12 @@ %define libsdocdir %{?_pkgdocdir:%(echo %{_pkgdocdir} | sed -e s,krb5,krb5-libs,g)}%{!?_pkgdocdir:%{_docdir}/%{name}-libs-%{version}} # Figure out where the default ccache lives and how we set it. -%global configure_default_ccache_name 1 %global configured_default_ccache_name KEYRING:persistent:%%{uid} Summary: The Kerberos network authentication system Name: krb5 Version: 1.15.1 -Release: 8%{?dist} +Release: 18%{?dist} # - Maybe we should explode from the now-available-to-everybody tarball instead? # http://web.mit.edu/kerberos/dist/krb5/1.13/krb5-1.13.2-signed.tar @@ -64,11 +63,31 @@ Patch146: krb5-1.11-run_user_0.patch Patch147: krb5-1.11-kpasswdtest.patch Patch148: Improve-PKINIT-UPN-SAN-matching.patch Patch149: Deindent-crypto_retrieve_X509_sans.patch -Patch151: krb5-kadm5clntmit_libsoname_version_downgrade.patch Patch152: Add-certauth-pluggable-interface.patch Patch153: Correct-error-handling-bug-in-prior-commit.patch Patch154: Add-the-client_name-kdcpreauth-callback.patch Patch155: Use-the-canonical-client-principal-name-for-OTP.patch +Patch156: Remove-incomplete-PKINIT-OCSP-support.patch +Patch157: Add-support-to-query-the-SSF-of-a-GSS-context.patch +Patch158: Add-k5test-expected_msg-expected_trace.patch +Patch159: Add-PKINIT-UPN-tests-to-t_pkinit.py.patch +Patch160: Add-test-cert-generation-to-make-certs.sh.patch +Patch161: Fix-make-certs.sh-for-OpenSSL-1.1.patch +Patch162: Allow-clock-skew-in-krb5-gss_context_time.patch +Patch163: Fix-in_clock_skew-and-use-it-in-AS-client-code.patch +Patch164: Add-timestamp-helper-functions.patch +Patch165: Make-timestamp-manipulations-y2038-safe.patch +Patch166: Add-timestamp-tests.patch +Patch167: Add-y2038-documentation.patch +Patch168: Fix-more-time-manipulations-for-y2038.patch +Patch169: Use-krb5_timestamp-where-appropriate.patch +Patch170: Add-KDC-policy-pluggable-interface.patch +Patch171: Fix-bugs-in-kdcpolicy-commit.patch +Patch172: Prevent-KDC-unset-status-assertion-failures.patch +Patch173: Convert-some-pkiDebug-messages-to-TRACE-macros.patch +Patch174: Fix-certauth-built-in-module-returns.patch +Patch175: Add-test-cert-with-no-extensions.patch +Patch176: Expose-context-errors-in-pkinit_server_plugin_init.patch License: MIT URL: http://web.mit.edu/kerberos/www/ @@ -265,11 +284,31 @@ ONLY by kerberos itself. Do not depend on this package. %patch147 -p1 -b .krb5-1.11-kpasswdtest %patch148 -p1 -b .Improve-PKINIT-UPN-SAN-matching %patch149 -p1 -b .Deindent-crypto_retrieve_X509_sans -%patch151 -p1 -b .krb5-kadm5clntmit_libsoname_version_downgrade %patch152 -p1 -b .Add-certauth-pluggable-interface %patch153 -p1 -b .Correct-error-handling-bug-in-prior-commit %patch154 -p1 -b .Add-the-client_name-kdcpreauth-callback %patch155 -p1 -b .Use-the-canonical-client-principal-name-for-OTP +%patch156 -p1 -b .Remove-incomplete-PKINIT-OCSP-support +%patch157 -p1 -b .Add-support-to-query-the-SSF-of-a-GSS-context +%patch158 -p1 -b .Add-k5test-expected_msg-expected_trace +%patch159 -p1 -b .Add-PKINIT-UPN-tests-to-t_pkinit.py +%patch160 -p1 -b .Add-test-cert-generation-to-make-certs.sh +%patch161 -p1 -b .Fix-make-certs.sh-for-OpenSSL-1.1 +%patch162 -p1 -b .Allow-clock-skew-in-krb5-gss_context_time +%patch163 -p1 -b .Fix-in_clock_skew-and-use-it-in-AS-client-code +%patch164 -p1 -b .Add-timestamp-helper-functions +%patch165 -p1 -b .Make-timestamp-manipulations-y2038-safe +%patch166 -p1 -b .Add-timestamp-tests +%patch167 -p1 -b .Add-y2038-documentation +%patch168 -p1 -b .Fix-more-time-manipulations-for-y2038 +%patch169 -p1 -b .Use-krb5_timestamp-where-appropriate +%patch170 -p1 -b .Add-KDC-policy-pluggable-interface +%patch171 -p1 -b .Fix-bugs-in-kdcpolicy-commit +%patch172 -p1 -b .Prevent-KDC-unset-status-assertion-failures +%patch173 -p1 -b .Convert-some-pkiDebug-messages-to-TRACE-macros +%patch174 -p1 -b .Fix-certauth-built-in-module-returns +%patch175 -p1 -b .Add-test-cert-with-no-extensions +%patch176 -p1 -b .Expose-context-errors-in-pkinit_server_plugin_init ln NOTICE LICENSE @@ -453,14 +492,12 @@ mkdir -m 755 -p $RPM_BUILD_ROOT/etc/gss/mech.d # If the default configuration needs to start specifying a default cache # location, add it now, then fixup the timestamp so that it looks the same. -%if 0%{?configure_default_ccache_name} DEFCCNAME="%{configured_default_ccache_name}"; export DEFCCNAME awk '{print} /^# default_realm/{print " default_ccache_name =", ENVIRON["DEFCCNAME"]}' \ %{SOURCE6} > $RPM_BUILD_ROOT/etc/krb5.conf touch -r %{SOURCE6} $RPM_BUILD_ROOT/etc/krb5.conf grep default_ccache_name $RPM_BUILD_ROOT/etc/krb5.conf -%endif # Server init scripts (krb5kdc,kadmind,kpropd) and their sysconfig files. mkdir -p $RPM_BUILD_ROOT%{_unitdir} @@ -557,51 +594,10 @@ rm -- "$RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/preauth/test.so" %post libs -p /sbin/ldconfig -%if 0%{?configure_default_ccache_name} -%triggerun libs -- krb5-libs < 1.11.3-16 -# Triggered roughly on the version where this logic was introduced. -# Try to add a default_ccache_name to /etc/krb5.conf, removing the previous -# default which we configured, if we find it. -DEFCCNAME="%{configured_default_ccache_name}"; export DEFCCNAME -tmpfile=`mktemp /etc/krb5.conf.XXXXXX` -if test -z "$tmpfile" ; then - # Give up. - exit 0 -fi -# Remove the default value we previously set. Be very exact about it. -if grep -q default_ccache_name /etc/krb5.conf ; then - sed -r '/^ default_ccache_name = DIR:\/run\/user\/%%\{uid\}\/krb5cc$/d' /etc/krb5.conf > "$tmpfile" - if test -s "$tmpfile" ; then - if touch -r /etc/krb5.conf "$tmpfile" ; then - cat "$tmpfile" > /etc/krb5.conf - touch -r "$tmpfile" /etc/krb5.conf - fi - fi -fi -# Add the new default value, unless there's one set. Don't be too particular -# about it. -if ! grep -q default_ccache_name /etc/krb5.conf ; then - awk ' - /^\[.*\]$/ { - if (libdefaults) { - print " default_ccache_name =", ENVIRON["DEFCCNAME"] - print "" - } - libdefaults=0; - } - /^\[libdefaults\]$/ { libdefaults=1; } - { print }' /etc/krb5.conf > "$tmpfile" - if test -s "$tmpfile" ; then - if touch -r /etc/krb5.conf "$tmpfile" ; then - cat "$tmpfile" > /etc/krb5.conf - touch -r "$tmpfile" /etc/krb5.conf - fi - fi +%triggerun libs -- krb5-libs < 1.15.1-13 +if ! grep -q 'includedir /etc/krb5.conf.d' /etc/krb5.conf ; then + sed -i '1i # Other applications require this directory to perform krb5 configuration.\nincludedir /etc/krb5.conf.d/\n' /etc/krb5.conf fi -if test -n "$tmpfile" ; then - rm -f -- "$tmpfile" -fi -%endif %postun libs -p /sbin/ldconfig @@ -817,6 +813,47 @@ exit 0 %{_libdir}/libkadm5srv_mit.so.* %changelog +* Tue Nov 28 2017 Robbie Harwood - 1.15.1-18 +- Expose context errors in pkinit_server_plugin_init +- Resolves: #1460089 + +* Thu Nov 02 2017 Robbie Harwood - 1.15.1-17 +- Drop certauth test changes that prevented runnig it +- Resolves: #1498767 + +* Thu Nov 02 2017 Robbie Harwood - 1.15.1-16 +- Drop irrelevant DIR trigger logic +- Resolves: #1431198 + +* Thu Oct 05 2017 Robbie Harwood - 1.15.1-15 +- Fix CVE-2017-7562 (certauth eku bypass) +- Resolves: #1498767 + +* Thu Oct 05 2017 Robbie Harwood - 1.15.1-14 +- Fix CVE-2017-11368 (s4u2 request assertion failures) +- Resolves: #1498768 + +* Tue Oct 03 2017 Robbie Harwood - 1.15.1-13 +- Force-add /etc/krb5.conf.d so we can guarantee it exists +- Resolves: #1431198 + +* Tue Sep 26 2017 Robbie Harwood - 1.15.1-12 +- Add krb5 policy plugin interface +- Remove soname downgrade +- Resolves: #1462982 + +* Wed Sep 06 2017 Robbie Harwood - 1.15.1-11 +- Make t_certauth.py runnable +- Resolves: #1443388 + +* Tue Sep 05 2017 Robbie Harwood - 1.15.1-10 +- Add context SSF query support +- Resolves: #1472956 + +* Thu Aug 17 2017 Robbie Harwood - 1.15.1-9 +- Remove incomplete PKINIT OCSP support +- Resolves: #1460089 + * Fri Apr 28 2017 Robbie Harwood - 1.15.1-8 - Add kprop.service argument file - Resolves: #1389073