summaryrefslogtreecommitdiff
path: root/src/lib/gssapi/generic/util_seqstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gssapi/generic/util_seqstate.c')
-rw-r--r--src/lib/gssapi/generic/util_seqstate.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/lib/gssapi/generic/util_seqstate.c b/src/lib/gssapi/generic/util_seqstate.c
new file mode 100644
index 000000000000..a0bc2cc1c1d4
--- /dev/null
+++ b/src/lib/gssapi/generic/util_seqstate.c
@@ -0,0 +1,163 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/generic/util_seqstate.c - sequence number checking */
+/*
+ * Copyright (C) 2014 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 "gssapiP_generic.h"
+#include <string.h>
+
+struct g_seqnum_state_st {
+ /* Flags to indicate whether we are supposed to check for replays or
+ * enforce strict sequencing. */
+ int do_replay;
+ int do_sequence;
+
+ /* UINT32_MAX for 32-bit sequence numbers, UINT64_MAX for 64-bit. Mask
+ * against this after arithmetic to stay within the correct range. */
+ uint64_t seqmask;
+
+ /* The initial sequence number for this context. This value will be
+ * subtracted from all received sequence numbers to simplify wraparound. */
+ uint64_t base;
+
+ /* The expected next sequence number (one more than the highest previously
+ * seen sequence number), relative to base. */
+ uint64_t next;
+
+ /*
+ * A bitmap for the 64 sequence numbers prior to next. If the 1<<(i-1) bit
+ * is set, then we have seen seqnum next-i relative to base. The least
+ * significant bit is always set if we have received any sequence numbers,
+ * and indicates the highest sequence number we have seen (next-1). When
+ * we advance next, we shift recvmap to the left.
+ */
+ uint64_t recvmap;
+};
+
+long
+g_seqstate_init(g_seqnum_state *state_out, uint64_t seqnum, int do_replay,
+ int do_sequence, int wide)
+{
+ g_seqnum_state state;
+
+ *state_out = NULL;
+ state = malloc(sizeof(*state));
+ if (state == NULL)
+ return ENOMEM;
+ state->do_replay = do_replay;
+ state->do_sequence = do_sequence;
+ state->seqmask = wide ? UINT64_MAX : UINT32_MAX;
+ state->base = seqnum;
+ state->next = state->recvmap = 0;
+ *state_out = state;
+ return 0;
+}
+
+OM_uint32
+g_seqstate_check(g_seqnum_state state, uint64_t seqnum)
+{
+ uint64_t rel_seqnum, offset, bit;
+
+ if (!state->do_replay && !state->do_sequence)
+ return GSS_S_COMPLETE;
+
+ /* Use the difference from the base seqnum, to simplify wraparound. */
+ rel_seqnum = (seqnum - state->base) & state->seqmask;
+
+ if (rel_seqnum >= state->next) {
+ /* seqnum is the expected sequence number or in the future. Update the
+ * received bitmap and expected next sequence number. */
+ offset = rel_seqnum - state->next;
+ state->recvmap = (state->recvmap << (offset + 1)) | 1;
+ state->next = (rel_seqnum + 1) & state->seqmask;
+
+ return (offset > 0 && state->do_sequence) ? GSS_S_GAP_TOKEN :
+ GSS_S_COMPLETE;
+ }
+
+ /* seqnum is in the past. Check if it's too old for replay detection. */
+ offset = state->next - rel_seqnum;
+ if (offset > 64)
+ return state->do_sequence ? GSS_S_UNSEQ_TOKEN : GSS_S_OLD_TOKEN;
+
+ /* Check for replay and mark as received. */
+ bit = (uint64_t)1 << (offset - 1);
+ if (state->do_replay && (state->recvmap & bit))
+ return GSS_S_DUPLICATE_TOKEN;
+ state->recvmap |= bit;
+
+ return state->do_sequence ? GSS_S_UNSEQ_TOKEN : GSS_S_COMPLETE;
+}
+
+void
+g_seqstate_free(g_seqnum_state state)
+{
+ free(state);
+}
+
+/*
+ * These support functions are for the serialization routines
+ */
+void
+g_seqstate_size(g_seqnum_state state, size_t *sizep)
+{
+ *sizep += sizeof(*state);
+}
+
+long
+g_seqstate_externalize(g_seqnum_state state, unsigned char **buf,
+ size_t *lenremain)
+{
+ if (*lenremain < sizeof(*state))
+ return ENOMEM;
+ memcpy(*buf, state, sizeof(*state));
+ *buf += sizeof(*state);
+ *lenremain -= sizeof(*state);
+ return 0;
+}
+
+long
+g_seqstate_internalize(g_seqnum_state *state_out, unsigned char **buf,
+ size_t *lenremain)
+{
+ g_seqnum_state state;
+
+ *state_out = NULL;
+ if (*lenremain < sizeof(*state))
+ return EINVAL;
+ state = malloc(sizeof(*state));
+ if (state == NULL)
+ return ENOMEM;
+ memcpy(state, *buf, sizeof(*state));
+ *buf += sizeof(*state);
+ *lenremain -= sizeof(*state);
+ *state_out = state;
+ return 0;
+}