Path: blob/main/crypto/krb5/src/lib/gssapi/generic/util_seqstate.c
39562 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* lib/gssapi/generic/util_seqstate.c - sequence number checking */2/*3* Copyright (C) 2014 by the Massachusetts Institute of Technology.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9*10* * Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in15* the documentation and/or other materials provided with the16* distribution.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS19* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT20* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS21* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE22* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,23* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES24* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR25* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,27* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED29* OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132#include "gssapiP_generic.h"33#include <string.h>3435struct g_seqnum_state_st {36/* Flags to indicate whether we are supposed to check for replays or37* enforce strict sequencing. */38int do_replay;39int do_sequence;4041/* UINT32_MAX for 32-bit sequence numbers, UINT64_MAX for 64-bit. Mask42* against this after arithmetic to stay within the correct range. */43uint64_t seqmask;4445/* The initial sequence number for this context. This value will be46* subtracted from all received sequence numbers to simplify wraparound. */47uint64_t base;4849/* The expected next sequence number (one more than the highest previously50* seen sequence number), relative to base. */51uint64_t next;5253/*54* A bitmap for the 64 sequence numbers prior to next. If the 1<<(i-1) bit55* is set, then we have seen seqnum next-i relative to base. The least56* significant bit is always set if we have received any sequence numbers,57* and indicates the highest sequence number we have seen (next-1). When58* we advance next, we shift recvmap to the left.59*/60uint64_t recvmap;61};6263long64g_seqstate_init(g_seqnum_state *state_out, uint64_t seqnum, int do_replay,65int do_sequence, int wide)66{67g_seqnum_state state;6869*state_out = NULL;70state = malloc(sizeof(*state));71if (state == NULL)72return ENOMEM;73state->do_replay = do_replay;74state->do_sequence = do_sequence;75state->seqmask = wide ? UINT64_MAX : UINT32_MAX;76state->base = seqnum;77state->next = state->recvmap = 0;78*state_out = state;79return 0;80}8182OM_uint3283g_seqstate_check(g_seqnum_state state, uint64_t seqnum)84{85uint64_t rel_seqnum, offset, bit;8687if (!state->do_replay && !state->do_sequence)88return GSS_S_COMPLETE;8990/* Use the difference from the base seqnum, to simplify wraparound. */91rel_seqnum = (seqnum - state->base) & state->seqmask;9293if (rel_seqnum >= state->next) {94/* seqnum is the expected sequence number or in the future. Update the95* received bitmap and expected next sequence number. */96offset = rel_seqnum - state->next;97state->recvmap = (state->recvmap << (offset + 1)) | 1;98state->next = (rel_seqnum + 1) & state->seqmask;99100return (offset > 0 && state->do_sequence) ? GSS_S_GAP_TOKEN :101GSS_S_COMPLETE;102}103104/* seqnum is in the past. Check if it's too old for replay detection. */105offset = state->next - rel_seqnum;106if (offset > 64)107return state->do_sequence ? GSS_S_UNSEQ_TOKEN : GSS_S_OLD_TOKEN;108109/* Check for replay and mark as received. */110bit = (uint64_t)1 << (offset - 1);111if (state->do_replay && (state->recvmap & bit))112return GSS_S_DUPLICATE_TOKEN;113state->recvmap |= bit;114115return state->do_sequence ? GSS_S_UNSEQ_TOKEN : GSS_S_COMPLETE;116}117118void119g_seqstate_free(g_seqnum_state state)120{121free(state);122}123124/*125* These support functions are for the serialization routines126*/127void128g_seqstate_size(g_seqnum_state state, size_t *sizep)129{130*sizep += sizeof(*state);131}132133long134g_seqstate_externalize(g_seqnum_state state, unsigned char **buf,135size_t *lenremain)136{137if (*lenremain < sizeof(*state))138return ENOMEM;139memcpy(*buf, state, sizeof(*state));140*buf += sizeof(*state);141*lenremain -= sizeof(*state);142return 0;143}144145long146g_seqstate_internalize(g_seqnum_state *state_out, unsigned char **buf,147size_t *lenremain)148{149g_seqnum_state state;150151*state_out = NULL;152if (*lenremain < sizeof(*state))153return EINVAL;154state = malloc(sizeof(*state));155if (state == NULL)156return ENOMEM;157memcpy(state, *buf, sizeof(*state));158*buf += sizeof(*state);159*lenremain -= sizeof(*state);160*state_out = state;161return 0;162}163164165