|
|
819f75 |
From 31d5c854198ed91fc2bd0b9fb87ed0dcd5a40eb6 Mon Sep 17 00:00:00 2001
|
|
|
819f75 |
From: Greg Hudson <ghudson@mit.edu>
|
|
|
819f75 |
Date: Thu, 24 Aug 2017 16:00:33 -0400
|
|
|
819f75 |
Subject: [PATCH] Limit ticket lifetime to 2^31-1 seconds
|
|
|
819f75 |
|
|
|
819f75 |
Although timestamps above 2^31-1 are now valid, intervals exceeding
|
|
|
819f75 |
2^31-1 seconds may be treated incorrectly by comparison operations.
|
|
|
819f75 |
|
|
|
819f75 |
The initially computed interval in kdc_get_ticket_endtime() could be
|
|
|
819f75 |
negative if the requested end time is far in the future, causing the
|
|
|
819f75 |
function to yield an incorrect result. (With the new larger value of
|
|
|
819f75 |
kdc_infinity, this could specifically happen if a KDC-REQ contains a
|
|
|
819f75 |
zero till field.) Cap the interval at the maximum valid value.
|
|
|
819f75 |
Reported by Weijun Wang.
|
|
|
819f75 |
|
|
|
819f75 |
Avoid delta comparisons in favor of timestamp comparions in
|
|
|
819f75 |
krb5int_validate_times(), ksu's krb5_check_exp(), and clockskew
|
|
|
819f75 |
checks.
|
|
|
819f75 |
|
|
|
819f75 |
Also use a y2038-safe timestamp comparison in set_request_times() when
|
|
|
819f75 |
comparing the requested renewable end time to the requested ticket end
|
|
|
819f75 |
time.
|
|
|
819f75 |
|
|
|
819f75 |
ticket: 8352
|
|
|
819f75 |
(cherry picked from commit 54e58755368b58ba5894a14c1d02626da42d8003)
|
|
|
819f75 |
---
|
|
|
819f75 |
src/clients/ksu/ccache.c | 2 +-
|
|
|
819f75 |
src/include/k5-int.h | 7 +++++++
|
|
|
819f75 |
src/kdc/kdc_util.c | 7 ++++++-
|
|
|
819f75 |
src/kdc/replay.c | 2 +-
|
|
|
819f75 |
src/kdc/t_replay.c | 2 +-
|
|
|
819f75 |
src/lib/krb5/krb/gc_via_tkt.c | 4 ++--
|
|
|
819f75 |
src/lib/krb5/krb/get_in_tkt.c | 6 +++---
|
|
|
819f75 |
src/lib/krb5/krb/int-proto.h | 3 ---
|
|
|
819f75 |
src/lib/krb5/krb/valid_times.c | 4 ++--
|
|
|
819f75 |
src/lib/krb5/os/timeofday.c | 2 +-
|
|
|
819f75 |
10 files changed, 24 insertions(+), 15 deletions(-)
|
|
|
819f75 |
|
|
|
819f75 |
diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c
|
|
|
819f75 |
index 236313b7b..2a99521d4 100644
|
|
|
819f75 |
--- a/src/clients/ksu/ccache.c
|
|
|
819f75 |
+++ b/src/clients/ksu/ccache.c
|
|
|
819f75 |
@@ -282,7 +282,7 @@ krb5_error_code krb5_check_exp(context, tkt_time)
|
|
|
819f75 |
|
|
|
819f75 |
}
|
|
|
819f75 |
|
|
|
819f75 |
- if (ts_delta(currenttime, tkt_time.endtime) > context->clockskew) {
|
|
|
819f75 |
+ if (ts_after(currenttime, ts_incr(tkt_time.endtime, context->clockskew))) {
|
|
|
819f75 |
retval = KRB5KRB_AP_ERR_TKT_EXPIRED ;
|
|
|
819f75 |
return retval;
|
|
|
819f75 |
}
|
|
|
819f75 |
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
|
|
|
819f75 |
index 39ffb9568..e31004a7c 100644
|
|
|
819f75 |
--- a/src/include/k5-int.h
|
|
|
819f75 |
+++ b/src/include/k5-int.h
|
|
|
819f75 |
@@ -2386,6 +2386,13 @@ ts_after(krb5_timestamp a, krb5_timestamp b)
|
|
|
819f75 |
return (uint32_t)a > (uint32_t)b;
|
|
|
819f75 |
}
|
|
|
819f75 |
|
|
|
819f75 |
+/* Return true if a and b are within d seconds. */
|
|
|
819f75 |
+static inline krb5_boolean
|
|
|
819f75 |
+ts_within(krb5_timestamp a, krb5_timestamp b, krb5_deltat d)
|
|
|
819f75 |
+{
|
|
|
819f75 |
+ return !ts_after(a, ts_incr(b, d)) && !ts_after(b, ts_incr(a, d));
|
|
|
819f75 |
+}
|
|
|
819f75 |
+
|
|
|
819f75 |
krb5_error_code KRB5_CALLCONV
|
|
|
819f75 |
krb5_get_credentials_for_user(krb5_context context, krb5_flags options,
|
|
|
819f75 |
krb5_ccache ccache,
|
|
|
819f75 |
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
|
|
|
819f75 |
index 5455e2a67..770163b94 100644
|
|
|
819f75 |
--- a/src/kdc/kdc_util.c
|
|
|
819f75 |
+++ b/src/kdc/kdc_util.c
|
|
|
819f75 |
@@ -1759,14 +1759,19 @@ kdc_get_ticket_endtime(kdc_realm_t *kdc_active_realm,
|
|
|
819f75 |
krb5_db_entry *server,
|
|
|
819f75 |
krb5_timestamp *out_endtime)
|
|
|
819f75 |
{
|
|
|
819f75 |
- krb5_timestamp until, life;
|
|
|
819f75 |
+ krb5_timestamp until;
|
|
|
819f75 |
+ krb5_deltat life;
|
|
|
819f75 |
|
|
|
819f75 |
if (till == 0)
|
|
|
819f75 |
till = kdc_infinity;
|
|
|
819f75 |
|
|
|
819f75 |
until = ts_min(till, endtime);
|
|
|
819f75 |
|
|
|
819f75 |
+ /* Determine the requested lifetime, capped at the maximum valid time
|
|
|
819f75 |
+ * interval. */
|
|
|
819f75 |
life = ts_delta(until, starttime);
|
|
|
819f75 |
+ if (ts_after(until, starttime) && life < 0)
|
|
|
819f75 |
+ life = INT32_MAX;
|
|
|
819f75 |
|
|
|
819f75 |
if (client != NULL && client->max_life != 0)
|
|
|
819f75 |
life = min(life, client->max_life);
|
|
|
819f75 |
diff --git a/src/kdc/replay.c b/src/kdc/replay.c
|
|
|
819f75 |
index fab39cf88..caca783bf 100644
|
|
|
819f75 |
--- a/src/kdc/replay.c
|
|
|
819f75 |
+++ b/src/kdc/replay.c
|
|
|
819f75 |
@@ -61,7 +61,7 @@ static size_t total_size = 0;
|
|
|
819f75 |
static krb5_ui_4 seed;
|
|
|
819f75 |
|
|
|
819f75 |
#define STALE_TIME (2*60) /* two minutes */
|
|
|
819f75 |
-#define STALE(ptr, now) (labs(ts_delta((ptr)->timein, now)) >= STALE_TIME)
|
|
|
819f75 |
+#define STALE(ptr, now) (ts_after(now, ts_incr((ptr)->timein, STALE_TIME)))
|
|
|
819f75 |
|
|
|
819f75 |
/* Return x rotated to the left by r bits. */
|
|
|
819f75 |
static inline krb5_ui_4
|
|
|
819f75 |
diff --git a/src/kdc/t_replay.c b/src/kdc/t_replay.c
|
|
|
819f75 |
index 1442e0e8c..bb7e2faff 100644
|
|
|
819f75 |
--- a/src/kdc/t_replay.c
|
|
|
819f75 |
+++ b/src/kdc/t_replay.c
|
|
|
819f75 |
@@ -903,7 +903,7 @@ test_kdc_insert_lookaside_cache_expire(void **state)
|
|
|
819f75 |
assert_non_null(e);
|
|
|
819f75 |
e->num_hits = 5;
|
|
|
819f75 |
|
|
|
819f75 |
- time_return(STALE_TIME, 0);
|
|
|
819f75 |
+ time_return(STALE_TIME + 1, 0);
|
|
|
819f75 |
kdc_insert_lookaside(context, &req2, NULL);
|
|
|
819f75 |
|
|
|
819f75 |
assert_null(K5_LIST_FIRST(&hash_table[req_hash1]));
|
|
|
819f75 |
diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c
|
|
|
819f75 |
index cf1ea361f..5b9bb9573 100644
|
|
|
819f75 |
--- a/src/lib/krb5/krb/gc_via_tkt.c
|
|
|
819f75 |
+++ b/src/lib/krb5/krb/gc_via_tkt.c
|
|
|
819f75 |
@@ -306,8 +306,8 @@ krb5int_process_tgs_reply(krb5_context context,
|
|
|
819f75 |
goto cleanup;
|
|
|
819f75 |
|
|
|
819f75 |
if (!in_cred->times.starttime &&
|
|
|
819f75 |
- !in_clock_skew(context, dec_rep->enc_part2->times.starttime,
|
|
|
819f75 |
- timestamp)) {
|
|
|
819f75 |
+ !ts_within(dec_rep->enc_part2->times.starttime, timestamp,
|
|
|
819f75 |
+ context->clockskew)) {
|
|
|
819f75 |
retval = KRB5_KDCREP_SKEW;
|
|
|
819f75 |
goto cleanup;
|
|
|
819f75 |
}
|
|
|
819f75 |
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
|
|
|
819f75 |
index 7178bd87b..ed15550f0 100644
|
|
|
819f75 |
--- a/src/lib/krb5/krb/get_in_tkt.c
|
|
|
819f75 |
+++ b/src/lib/krb5/krb/get_in_tkt.c
|
|
|
819f75 |
@@ -269,8 +269,8 @@ verify_as_reply(krb5_context context,
|
|
|
819f75 |
return retval;
|
|
|
819f75 |
} else {
|
|
|
819f75 |
if ((request->from == 0) &&
|
|
|
819f75 |
- !in_clock_skew(context, as_reply->enc_part2->times.starttime,
|
|
|
819f75 |
- time_now))
|
|
|
819f75 |
+ !ts_within(as_reply->enc_part2->times.starttime, time_now,
|
|
|
819f75 |
+ context->clockskew))
|
|
|
819f75 |
return (KRB5_KDCREP_SKEW);
|
|
|
819f75 |
}
|
|
|
819f75 |
return 0;
|
|
|
819f75 |
@@ -781,7 +781,7 @@ set_request_times(krb5_context context, krb5_init_creds_context ctx)
|
|
|
819f75 |
if (ctx->renew_life > 0) {
|
|
|
819f75 |
/* Don't ask for a smaller renewable time than the lifetime. */
|
|
|
819f75 |
ctx->request->rtime = ts_incr(from, ctx->renew_life);
|
|
|
819f75 |
- if (ctx->request->rtime < ctx->request->till)
|
|
|
819f75 |
+ if (ts_after(ctx->request->till, ctx->request->rtime))
|
|
|
819f75 |
ctx->request->rtime = ctx->request->till;
|
|
|
819f75 |
ctx->request->kdc_options &= ~KDC_OPT_RENEWABLE_OK;
|
|
|
819f75 |
} else {
|
|
|
819f75 |
diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
|
|
|
819f75 |
index 48bd9f8f7..9c746d05b 100644
|
|
|
819f75 |
--- a/src/lib/krb5/krb/int-proto.h
|
|
|
819f75 |
+++ b/src/lib/krb5/krb/int-proto.h
|
|
|
819f75 |
@@ -83,9 +83,6 @@ krb5int_construct_matching_creds(krb5_context context, krb5_flags options,
|
|
|
819f75 |
krb5_creds *in_creds, krb5_creds *mcreds,
|
|
|
819f75 |
krb5_flags *fields);
|
|
|
819f75 |
|
|
|
819f75 |
-#define in_clock_skew(context, date, now) \
|
|
|
819f75 |
- (labs(ts_delta(date, now)) < (context)->clockskew)
|
|
|
819f75 |
-
|
|
|
819f75 |
#define IS_TGS_PRINC(p) ((p)->length == 2 && \
|
|
|
819f75 |
data_eq_string((p)->data[0], KRB5_TGS_NAME))
|
|
|
819f75 |
|
|
|
819f75 |
diff --git a/src/lib/krb5/krb/valid_times.c b/src/lib/krb5/krb/valid_times.c
|
|
|
819f75 |
index 9e509b2dd..294761a88 100644
|
|
|
819f75 |
--- a/src/lib/krb5/krb/valid_times.c
|
|
|
819f75 |
+++ b/src/lib/krb5/krb/valid_times.c
|
|
|
819f75 |
@@ -47,10 +47,10 @@ krb5int_validate_times(krb5_context context, krb5_ticket_times *times)
|
|
|
819f75 |
else
|
|
|
819f75 |
starttime = times->authtime;
|
|
|
819f75 |
|
|
|
819f75 |
- if (ts_delta(starttime, currenttime) > context->clockskew)
|
|
|
819f75 |
+ if (ts_after(starttime, ts_incr(currenttime, context->clockskew)))
|
|
|
819f75 |
return KRB5KRB_AP_ERR_TKT_NYV; /* ticket not yet valid */
|
|
|
819f75 |
|
|
|
819f75 |
- if (ts_delta(currenttime, times->endtime) > context->clockskew)
|
|
|
819f75 |
+ if (ts_after(currenttime, ts_incr(times->endtime, context->clockskew)))
|
|
|
819f75 |
return KRB5KRB_AP_ERR_TKT_EXPIRED; /* ticket expired */
|
|
|
819f75 |
|
|
|
819f75 |
return 0;
|
|
|
819f75 |
diff --git a/src/lib/krb5/os/timeofday.c b/src/lib/krb5/os/timeofday.c
|
|
|
819f75 |
index 887f24c22..d4e36b1c7 100644
|
|
|
819f75 |
--- a/src/lib/krb5/os/timeofday.c
|
|
|
819f75 |
+++ b/src/lib/krb5/os/timeofday.c
|
|
|
819f75 |
@@ -60,7 +60,7 @@ krb5_check_clockskew(krb5_context context, krb5_timestamp date)
|
|
|
819f75 |
retval = krb5_timeofday(context, ¤ttime);
|
|
|
819f75 |
if (retval)
|
|
|
819f75 |
return retval;
|
|
|
819f75 |
- if (labs(ts_delta(date, currenttime)) >= context->clockskew)
|
|
|
819f75 |
+ if (!ts_within(date, currenttime, context->clockskew))
|
|
|
819f75 |
return KRB5KRB_AP_ERR_SKEW;
|
|
|
819f75 |
|
|
|
819f75 |
return 0;
|