--- /dev/null
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/gssapi/generic/t_seqstate.c - Test program for sequence number state */
+/*
+ * 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"
+
+enum resultcode {
+ NOERR = GSS_S_COMPLETE,
+ GAP = GSS_S_GAP_TOKEN,
+ UNSEQ = GSS_S_UNSEQ_TOKEN,
+ OLD = GSS_S_OLD_TOKEN,
+ REPLAY = GSS_S_DUPLICATE_TOKEN
+};
+
+enum replayflag { NO_REPLAY = 0, DO_REPLAY = 1 };
+enum sequenceflag { NO_SEQUENCE = 0, DO_SEQUENCE = 1 };
+enum width { NARROW = 0, WIDE = 1, BOTH = 2 };
+
+struct test {
+ uint64_t initial;
+ enum replayflag do_replay;
+ enum sequenceflag do_sequence;
+ enum width wide_seqnums;
+ size_t nseqs;
+ struct {
+ uint64_t seqnum;
+ enum resultcode result;
+ } seqs[10];
+} tests[] = {
+ /* No replay or sequence checking. */
+ {
+ 10, NO_REPLAY, NO_SEQUENCE, BOTH,
+ 4, { { 11, NOERR }, { 10, NOERR }, { 10, NOERR }, { 9, NOERR } }
+ },
+
+ /* Basic sequence checking, no wraparound. */
+ {
+ 100, NO_REPLAY, DO_SEQUENCE, BOTH,
+ 4, { { 100, NOERR }, { 102, GAP }, { 103, NOERR }, { 101, UNSEQ } }
+ },
+
+ /* Initial gap sequence checking, no wraparound. */
+ {
+ 200, NO_REPLAY, DO_SEQUENCE, BOTH,
+ 4, { { 201, GAP }, { 202, NOERR }, { 200, UNSEQ }, { 203, NOERR } }
+ },
+
+ /* Sequence checking with wraparound. */
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, NARROW,
+ 4, { { UINT32_MAX - 1, NOERR }, { UINT32_MAX, NOERR }, { 0, NOERR },
+ { 1, NOERR } }
+ },
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, NARROW,
+ 4, { { UINT32_MAX - 1, NOERR }, { 0, GAP }, { UINT32_MAX, UNSEQ },
+ { 1, NOERR } }
+ },
+ {
+ UINT64_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 4, { { UINT64_MAX - 1, NOERR }, { UINT64_MAX, NOERR }, { 0, NOERR },
+ { 1, NOERR } }
+ },
+ {
+ UINT64_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 4, { { UINT64_MAX - 1, NOERR }, { 0, GAP }, { UINT64_MAX, UNSEQ },
+ { 1, NOERR } }
+ },
+
+ /* 64-bit sequence checking beyond 32-bit range */
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 4, { { UINT32_MAX - 1, NOERR },
+ { UINT32_MAX, NOERR },
+ { (uint64_t)UINT32_MAX + 1, NOERR },
+ { (uint64_t)UINT32_MAX + 2, NOERR } }
+ },
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 4, { { UINT32_MAX - 1, NOERR },
+ { (uint64_t)UINT32_MAX + 1, GAP },
+ { UINT32_MAX, UNSEQ },
+ { (uint64_t)UINT32_MAX + 2, NOERR } }
+ },
+ {
+ UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
+ 3, { { UINT32_MAX - 1, NOERR }, { UINT32_MAX, NOERR }, { 0, GAP } }
+ },
+
+ /* Replay without the replay flag set. Current code reports a replay
+ * anyway. */
+ {
+ 250, NO_REPLAY, DO_SEQUENCE, BOTH,
+ 2, { { 250, NOERR }, { 250, REPLAY } }
+ },
+
+ /* Basic replay detection with and without sequence checking. */
+ {
+ 0, DO_REPLAY, DO_SEQUENCE, BOTH,
+ 10, { { 5, GAP }, { 3, UNSEQ }, { 8, GAP }, { 3, REPLAY },
+ { 0, UNSEQ }, { 0, REPLAY }, { 5, REPLAY }, { 3, REPLAY },
+ { 8, REPLAY }, { 9, NOERR } }
+ },
+ {
+ 0, DO_REPLAY, NO_SEQUENCE, BOTH,
+ 10, { { 5, NOERR }, { 3, NOERR }, { 8, NOERR }, { 3, REPLAY },
+ { 0, NOERR }, { 0, REPLAY }, { 5, REPLAY }, { 3, REPLAY },
+ { 8, REPLAY }, { 9, NOERR } }
+ },
+
+ /* Replay and sequence detection with wraparound. The last seqnum produces
+ * GAP because it is before the initial sequence number. */
+ {
+ UINT64_MAX - 5, DO_REPLAY, DO_SEQUENCE, WIDE,
+ 10, { { UINT64_MAX, GAP }, { UINT64_MAX - 2, UNSEQ }, { 0, NOERR },
+ { UINT64_MAX, REPLAY }, { UINT64_MAX, REPLAY },
+ { 2, GAP }, { 0, REPLAY }, { 1, UNSEQ },
+ { UINT64_MAX - 2, REPLAY }, { UINT64_MAX - 6, GAP } }
+ },
+ {
+ UINT32_MAX - 5, DO_REPLAY, DO_SEQUENCE, NARROW,
+ 10, { { UINT32_MAX, GAP }, { UINT32_MAX - 2, UNSEQ }, { 0, NOERR },
+ { UINT32_MAX, REPLAY }, { UINT32_MAX, REPLAY },
+ { 2, GAP }, { 0, REPLAY }, { 1, UNSEQ },
+ { UINT32_MAX - 2, REPLAY }, { UINT32_MAX - 6, GAP } }
+ },
+};
+
+int
+main()
+{
+ size_t i, j;
+ enum width w;
+ struct test *t;
+ void *seqstate;
+ OM_uint32 status;
+
+ for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
+ t = &tests[i];
+ /* Try both widths if t->wide_seqnums is both, otherwise just one. */
+ for (w = NARROW; w <= WIDE; w++) {
+ if (t->wide_seqnums != BOTH && t->wide_seqnums != w)
+ continue;
+ if (g_order_init(&seqstate, t->initial, t->do_replay,
+ t->do_sequence, w))
+ abort();
+ for (j = 0; j < t->nseqs; j++) {
+ status = g_order_check(&seqstate, t->seqs[j].seqnum);
+ if (status != t->seqs[j].result) {
+ fprintf(stderr, "Test %d seq %d failed: %d != %d\n",
+ (int)i, (int)j, status, t->seqs[j].result);
+ return 1;
+ }
+ }
+ g_order_free(&seqstate);
+ }
+ }
+
+ return 0;
+}