xref: /freebsd/crypto/krb5/src/lib/gssapi/generic/t_seqstate.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/gssapi/generic/t_seqstate.c - Test program for sequence number state */
3 /*
4  * Copyright (C) 2014 by the Massachusetts Institute of Technology.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "gssapiP_generic.h"
34 
35 enum resultcode {
36     NOERR = GSS_S_COMPLETE,
37     GAP = GSS_S_GAP_TOKEN,
38     UNSEQ = GSS_S_UNSEQ_TOKEN,
39     OLD = GSS_S_OLD_TOKEN,
40     REPLAY = GSS_S_DUPLICATE_TOKEN
41 };
42 
43 enum replayflag { NO_REPLAY = 0, DO_REPLAY = 1 };
44 enum sequenceflag { NO_SEQUENCE = 0, DO_SEQUENCE = 1 };
45 enum width { NARROW = 0, WIDE = 1, BOTH = 2 };
46 
47 struct test {
48     uint64_t initial;
49     enum replayflag do_replay;
50     enum sequenceflag do_sequence;
51     enum width wide_seqnums;
52     size_t nseqs;
53     struct {
54         uint64_t seqnum;
55         enum resultcode result;
56     } seqs[10];
57 } tests[] = {
58     /* No replay or sequence checking. */
59     {
60         10, NO_REPLAY, NO_SEQUENCE, BOTH,
61         4, { { 11, NOERR }, { 10, NOERR }, { 10, NOERR }, { 9, NOERR } }
62     },
63 
64     /* Basic sequence checking, no wraparound. */
65     {
66         100, NO_REPLAY, DO_SEQUENCE, BOTH,
67         4, { { 100, NOERR }, { 102, GAP }, { 103, NOERR }, { 101, UNSEQ } }
68     },
69 
70     /* Initial gap sequence checking, no wraparound. */
71     {
72         200, NO_REPLAY, DO_SEQUENCE, BOTH,
73         4, { { 201, GAP }, { 202, NOERR }, { 200, UNSEQ }, { 203, NOERR } }
74     },
75 
76     /* Sequence checking with wraparound. */
77     {
78         UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, NARROW,
79         4, { { UINT32_MAX - 1, NOERR }, { UINT32_MAX, NOERR }, { 0, NOERR },
80              { 1, NOERR } }
81     },
82     {
83         UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, NARROW,
84         4, { { UINT32_MAX - 1, NOERR }, { 0, GAP }, { UINT32_MAX, UNSEQ },
85              { 1, NOERR } }
86     },
87     {
88         UINT64_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
89         4, { { UINT64_MAX - 1, NOERR }, { UINT64_MAX, NOERR }, { 0, NOERR },
90              { 1, NOERR } }
91     },
92     {
93         UINT64_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
94         4, { { UINT64_MAX - 1, NOERR }, { 0, GAP }, { UINT64_MAX, UNSEQ },
95              { 1, NOERR } }
96     },
97 
98     /* 64-bit sequence checking beyond 32-bit range */
99     {
100         UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
101         4, { { UINT32_MAX - 1, NOERR },
102              { UINT32_MAX, NOERR },
103              { (uint64_t)UINT32_MAX + 1, NOERR },
104              { (uint64_t)UINT32_MAX + 2, NOERR } }
105     },
106     {
107         UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
108         4, { { UINT32_MAX - 1, NOERR },
109              { (uint64_t)UINT32_MAX + 1, GAP },
110              { UINT32_MAX, UNSEQ },
111              { (uint64_t)UINT32_MAX + 2, NOERR } }
112     },
113     {
114         UINT32_MAX - 1, NO_REPLAY, DO_SEQUENCE, WIDE,
115         3, { { UINT32_MAX - 1, NOERR }, { UINT32_MAX, NOERR }, { 0, GAP } }
116     },
117 
118     /* Replay without the replay flag set. */
119     {
120         250, NO_REPLAY, DO_SEQUENCE, BOTH,
121         2, { { 250, NOERR }, { 250, UNSEQ } }
122     },
123 
124     /* Basic replay detection with and without sequence checking. */
125     {
126         0, DO_REPLAY, DO_SEQUENCE, BOTH,
127         10, { { 5, GAP }, { 3, UNSEQ }, { 8, GAP }, { 3, REPLAY },
128               { 0, UNSEQ }, { 0, REPLAY }, { 5, REPLAY }, { 3, REPLAY },
129               { 8, REPLAY }, { 9, NOERR } }
130     },
131     {
132         0, DO_REPLAY, NO_SEQUENCE, BOTH,
133         10, { { 5, NOERR }, { 3, NOERR }, { 8, NOERR }, { 3, REPLAY },
134               { 0, NOERR }, { 0, REPLAY }, { 5, REPLAY }, { 3, REPLAY },
135               { 8, REPLAY }, { 9, NOERR } }
136     },
137 
138     /* Replay and sequence detection with wraparound.  The last seqnum produces
139      * GAP because it is before the initial sequence number. */
140     {
141         UINT64_MAX - 5, DO_REPLAY, DO_SEQUENCE, WIDE,
142         10, { { UINT64_MAX, GAP }, { UINT64_MAX - 2, UNSEQ }, { 0, NOERR },
143               { UINT64_MAX, REPLAY }, { UINT64_MAX, REPLAY },
144               { 2, GAP }, { 0, REPLAY }, { 1, UNSEQ },
145               { UINT64_MAX - 2, REPLAY }, { UINT64_MAX - 6, GAP } }
146     },
147     {
148         UINT32_MAX - 5, DO_REPLAY, DO_SEQUENCE, NARROW,
149         10, { { UINT32_MAX, GAP }, { UINT32_MAX - 2, UNSEQ }, { 0, NOERR },
150               { UINT32_MAX, REPLAY }, { UINT32_MAX, REPLAY },
151               { 2, GAP }, { 0, REPLAY }, { 1, UNSEQ },
152               { UINT32_MAX - 2, REPLAY }, { UINT32_MAX - 6, GAP } }
153     },
154 
155     /* Old token edge cases.  The current code can detect replays up to 64
156      * numbers behind the expected sequence number (1164 in this case). */
157     {
158         1000, DO_REPLAY, NO_SEQUENCE, BOTH,
159         10, { { 1163, NOERR }, { 1100, NOERR }, { 1100, REPLAY },
160               { 1163, REPLAY }, { 1099, OLD }, { 1100, REPLAY },
161               { 1150, NOERR }, { 1150, REPLAY }, { 1000, OLD },
162               { 999, NOERR } }
163     },
164 };
165 
166 int
167 main()
168 {
169     size_t i, j;
170     enum width w;
171     struct test *t;
172     g_seqnum_state seqstate;
173     OM_uint32 status;
174 
175     for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
176         t = &tests[i];
177         /* Try both widths if t->wide_seqnums is both, otherwise just one. */
178         for (w = NARROW; w <= WIDE; w++) {
179             if (t->wide_seqnums != BOTH && t->wide_seqnums != w)
180                 continue;
181             if (g_seqstate_init(&seqstate, t->initial, t->do_replay,
182                                 t->do_sequence, w))
183                 abort();
184             for (j = 0; j < t->nseqs; j++) {
185                 status = g_seqstate_check(seqstate, t->seqs[j].seqnum);
186                 if (status != t->seqs[j].result) {
187                     fprintf(stderr, "Test %d seq %d failed: %d != %d\n",
188                             (int)i, (int)j, status, t->seqs[j].result);
189                     return 1;
190                 }
191             }
192             g_seqstate_free(seqstate);
193         }
194     }
195 
196     return 0;
197 }
198