netwerk/srtp/src/crypto/replay/rdbx.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * rdbx.c
michael@0 3 *
michael@0 4 * a replay database with extended range, using a rollover counter
michael@0 5 *
michael@0 6 * David A. McGrew
michael@0 7 * Cisco Systems, Inc.
michael@0 8 */
michael@0 9
michael@0 10 /*
michael@0 11 *
michael@0 12 * Copyright (c) 2001-2006, Cisco Systems, Inc.
michael@0 13 * All rights reserved.
michael@0 14 *
michael@0 15 * Redistribution and use in source and binary forms, with or without
michael@0 16 * modification, are permitted provided that the following conditions
michael@0 17 * are met:
michael@0 18 *
michael@0 19 * Redistributions of source code must retain the above copyright
michael@0 20 * notice, this list of conditions and the following disclaimer.
michael@0 21 *
michael@0 22 * Redistributions in binary form must reproduce the above
michael@0 23 * copyright notice, this list of conditions and the following
michael@0 24 * disclaimer in the documentation and/or other materials provided
michael@0 25 * with the distribution.
michael@0 26 *
michael@0 27 * Neither the name of the Cisco Systems, Inc. nor the names of its
michael@0 28 * contributors may be used to endorse or promote products derived
michael@0 29 * from this software without specific prior written permission.
michael@0 30 *
michael@0 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
michael@0 34 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
michael@0 35 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
michael@0 36 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
michael@0 37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
michael@0 38 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
michael@0 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
michael@0 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
michael@0 41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
michael@0 42 * OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 43 *
michael@0 44 */
michael@0 45
michael@0 46 #include "rdbx.h"
michael@0 47
michael@0 48
michael@0 49 /*
michael@0 50 * from RFC 3711:
michael@0 51 *
michael@0 52 * A receiver reconstructs the index i of a packet with sequence
michael@0 53 * number SEQ using the estimate
michael@0 54 *
michael@0 55 * i = 2^16 * v + SEQ,
michael@0 56 *
michael@0 57 * where v is chosen from the set { ROC-1, ROC, ROC+1 } such that i is
michael@0 58 * closest to the value 2^16 * ROC + s_l. If the value r+1 is used,
michael@0 59 * then the rollover counter r in the cryptographic context is
michael@0 60 * incremented by one (if the packet containing s is authentic).
michael@0 61 */
michael@0 62
michael@0 63
michael@0 64
michael@0 65 /*
michael@0 66 * rdbx implementation notes
michael@0 67 *
michael@0 68 * A xtd_seq_num_t is essentially a sequence number for which some of
michael@0 69 * the data on the wire are implicit. It logically consists of a
michael@0 70 * rollover counter and a sequence number; the sequence number is the
michael@0 71 * explicit part, and the rollover counter is the implicit part.
michael@0 72 *
michael@0 73 * Upon receiving a sequence_number (e.g. in a newly received SRTP
michael@0 74 * packet), the complete xtd_seq_num_t can be estimated by using a
michael@0 75 * local xtd_seq_num_t as a basis. This is done using the function
michael@0 76 * index_guess(&local, &guess, seq_from_packet). This function
michael@0 77 * returns the difference of the guess and the local value. The local
michael@0 78 * xtd_seq_num_t can be moved forward to the guess using the function
michael@0 79 * index_advance(&guess, delta), where delta is the difference.
michael@0 80 *
michael@0 81 *
michael@0 82 * A rdbx_t consists of a xtd_seq_num_t and a bitmask. The index is highest
michael@0 83 * sequence number that has been received, and the bitmask indicates
michael@0 84 * which of the recent indicies have been received as well. The
michael@0 85 * highest bit in the bitmask corresponds to the index in the bitmask.
michael@0 86 */
michael@0 87
michael@0 88
michael@0 89 void
michael@0 90 index_init(xtd_seq_num_t *pi) {
michael@0 91 #ifdef NO_64BIT_MATH
michael@0 92 *pi = make64(0,0);
michael@0 93 #else
michael@0 94 *pi = 0;
michael@0 95 #endif
michael@0 96 }
michael@0 97
michael@0 98 void
michael@0 99 index_advance(xtd_seq_num_t *pi, sequence_number_t s) {
michael@0 100 #ifdef NO_64BIT_MATH
michael@0 101 /* a > ~b means a+b will generate a carry */
michael@0 102 /* s is uint16 here */
michael@0 103 *pi = make64(high32(*pi) + (s > ~low32(*pi) ? 1 : 0),low32(*pi) + s);
michael@0 104 #else
michael@0 105 *pi += s;
michael@0 106 #endif
michael@0 107 }
michael@0 108
michael@0 109
michael@0 110 /*
michael@0 111 * index_guess(local, guess, s)
michael@0 112 *
michael@0 113 * given a xtd_seq_num_t local (which represents the last
michael@0 114 * known-to-be-good received xtd_seq_num_t) and a sequence number s
michael@0 115 * (from a newly arrived packet), sets the contents of *guess to
michael@0 116 * contain the best guess of the packet index to which s corresponds,
michael@0 117 * and returns the difference between *guess and *local
michael@0 118 *
michael@0 119 * nota bene - the output is a signed integer, DON'T cast it to a
michael@0 120 * unsigned integer!
michael@0 121 */
michael@0 122
michael@0 123 int
michael@0 124 index_guess(const xtd_seq_num_t *local,
michael@0 125 xtd_seq_num_t *guess,
michael@0 126 sequence_number_t s) {
michael@0 127 #ifdef NO_64BIT_MATH
michael@0 128 uint32_t local_roc = ((high32(*local) << 16) |
michael@0 129 (low32(*local) >> 16));
michael@0 130 uint16_t local_seq = (uint16_t) (low32(*local));
michael@0 131 #else
michael@0 132 uint32_t local_roc = (uint32_t)(*local >> 16);
michael@0 133 uint16_t local_seq = (uint16_t) *local;
michael@0 134 #endif
michael@0 135 #ifdef NO_64BIT_MATH
michael@0 136 uint32_t guess_roc = ((high32(*guess) << 16) |
michael@0 137 (low32(*guess) >> 16));
michael@0 138 uint16_t guess_seq = (uint16_t) (low32(*guess));
michael@0 139 #else
michael@0 140 uint32_t guess_roc = (uint32_t)(*guess >> 16);
michael@0 141 uint16_t guess_seq = (uint16_t) *guess;
michael@0 142 #endif
michael@0 143 int difference;
michael@0 144
michael@0 145 if (local_seq < seq_num_median) {
michael@0 146 if (s - local_seq > seq_num_median) {
michael@0 147 guess_roc = local_roc - 1;
michael@0 148 difference = seq_num_max - s + local_seq;
michael@0 149 } else {
michael@0 150 guess_roc = local_roc;
michael@0 151 difference = s - local_seq;
michael@0 152 }
michael@0 153 } else {
michael@0 154 if (local_seq - seq_num_median > s) {
michael@0 155 guess_roc = local_roc+1;
michael@0 156 difference = seq_num_max - local_seq + s;
michael@0 157 } else {
michael@0 158 difference = s - local_seq;
michael@0 159 guess_roc = local_roc;
michael@0 160 }
michael@0 161 }
michael@0 162 guess_seq = s;
michael@0 163
michael@0 164 /* Note: guess_roc is 32 bits, so this generates a 48-bit result! */
michael@0 165 #ifdef NO_64BIT_MATH
michael@0 166 *guess = make64(guess_roc >> 16,
michael@0 167 (guess_roc << 16) | guess_seq);
michael@0 168 #else
michael@0 169 *guess = (((uint64_t) guess_roc) << 16) | guess_seq;
michael@0 170 #endif
michael@0 171
michael@0 172 return difference;
michael@0 173 }
michael@0 174
michael@0 175 /*
michael@0 176 * rdbx
michael@0 177 *
michael@0 178 */
michael@0 179
michael@0 180
michael@0 181 /*
michael@0 182 * rdbx_init(&r, ws) initializes the rdbx_t pointed to by r with window size ws
michael@0 183 */
michael@0 184
michael@0 185 err_status_t
michael@0 186 rdbx_init(rdbx_t *rdbx, unsigned long ws) {
michael@0 187 if (ws == 0)
michael@0 188 return err_status_bad_param;
michael@0 189
michael@0 190 if (bitvector_alloc(&rdbx->bitmask, ws) != 0)
michael@0 191 return err_status_alloc_fail;
michael@0 192
michael@0 193 index_init(&rdbx->index);
michael@0 194
michael@0 195 return err_status_ok;
michael@0 196 }
michael@0 197
michael@0 198 /*
michael@0 199 * rdbx_dealloc(&r) frees memory for the rdbx_t pointed to by r
michael@0 200 */
michael@0 201
michael@0 202 err_status_t
michael@0 203 rdbx_dealloc(rdbx_t *rdbx) {
michael@0 204 bitvector_dealloc(&rdbx->bitmask);
michael@0 205
michael@0 206 return err_status_ok;
michael@0 207 }
michael@0 208
michael@0 209 /*
michael@0 210 * rdbx_set_roc(rdbx, roc) initalizes the rdbx_t at the location rdbx
michael@0 211 * to have the rollover counter value roc. If that value is less than
michael@0 212 * the current rollover counter value, then the function returns
michael@0 213 * err_status_replay_old; otherwise, err_status_ok is returned.
michael@0 214 *
michael@0 215 */
michael@0 216
michael@0 217 err_status_t
michael@0 218 rdbx_set_roc(rdbx_t *rdbx, uint32_t roc) {
michael@0 219 bitvector_set_to_zero(&rdbx->bitmask);
michael@0 220
michael@0 221 #ifdef NO_64BIT_MATH
michael@0 222 #error not yet implemented
michael@0 223 #else
michael@0 224
michael@0 225 /* make sure that we're not moving backwards */
michael@0 226 if (roc < (rdbx->index >> 16))
michael@0 227 return err_status_replay_old;
michael@0 228
michael@0 229 rdbx->index &= 0xffff; /* retain lowest 16 bits */
michael@0 230 rdbx->index |= ((uint64_t)roc) << 16; /* set ROC */
michael@0 231 #endif
michael@0 232
michael@0 233 return err_status_ok;
michael@0 234 }
michael@0 235
michael@0 236 /*
michael@0 237 * rdbx_get_packet_index(rdbx) returns the value of the packet index
michael@0 238 * for the rdbx_t pointed to by rdbx
michael@0 239 *
michael@0 240 */
michael@0 241
michael@0 242 xtd_seq_num_t
michael@0 243 rdbx_get_packet_index(const rdbx_t *rdbx) {
michael@0 244 return rdbx->index;
michael@0 245 }
michael@0 246
michael@0 247 /*
michael@0 248 * rdbx_get_window_size(rdbx) returns the value of the window size
michael@0 249 * for the rdbx_t pointed to by rdbx
michael@0 250 *
michael@0 251 */
michael@0 252
michael@0 253 unsigned long
michael@0 254 rdbx_get_window_size(const rdbx_t *rdbx) {
michael@0 255 return bitvector_get_length(&rdbx->bitmask);
michael@0 256 }
michael@0 257
michael@0 258 /*
michael@0 259 * rdbx_check(&r, delta) checks to see if the xtd_seq_num_t
michael@0 260 * which is at rdbx->index + delta is in the rdb
michael@0 261 */
michael@0 262
michael@0 263 err_status_t
michael@0 264 rdbx_check(const rdbx_t *rdbx, int delta) {
michael@0 265
michael@0 266 if (delta > 0) { /* if delta is positive, it's good */
michael@0 267 return err_status_ok;
michael@0 268 } else if ((int)(bitvector_get_length(&rdbx->bitmask) - 1) + delta < 0) {
michael@0 269 /* if delta is lower than the bitmask, it's bad */
michael@0 270 return err_status_replay_old;
michael@0 271 } else if (bitvector_get_bit(&rdbx->bitmask,
michael@0 272 (int)(bitvector_get_length(&rdbx->bitmask) - 1) + delta) == 1) {
michael@0 273 /* delta is within the window, so check the bitmask */
michael@0 274 return err_status_replay_fail;
michael@0 275 }
michael@0 276 /* otherwise, the index is okay */
michael@0 277
michael@0 278 return err_status_ok;
michael@0 279 }
michael@0 280
michael@0 281 /*
michael@0 282 * rdbx_add_index adds the xtd_seq_num_t at rdbx->window_start + d to
michael@0 283 * replay_db (and does *not* check if that xtd_seq_num_t appears in db)
michael@0 284 *
michael@0 285 * this function should be called only after replay_check has
michael@0 286 * indicated that the index does not appear in the rdbx, e.g., a mutex
michael@0 287 * should protect the rdbx between these calls if need be
michael@0 288 */
michael@0 289
michael@0 290 err_status_t
michael@0 291 rdbx_add_index(rdbx_t *rdbx, int delta) {
michael@0 292
michael@0 293 if (delta > 0) {
michael@0 294 /* shift forward by delta */
michael@0 295 index_advance(&rdbx->index, delta);
michael@0 296 bitvector_left_shift(&rdbx->bitmask, delta);
michael@0 297 bitvector_set_bit(&rdbx->bitmask, bitvector_get_length(&rdbx->bitmask) - 1);
michael@0 298 } else {
michael@0 299 /* delta is in window */
michael@0 300 bitvector_set_bit(&rdbx->bitmask, bitvector_get_length(&rdbx->bitmask) -1 + delta);
michael@0 301 }
michael@0 302
michael@0 303 /* note that we need not consider the case that delta == 0 */
michael@0 304
michael@0 305 return err_status_ok;
michael@0 306 }
michael@0 307
michael@0 308
michael@0 309
michael@0 310 /*
michael@0 311 * rdbx_estimate_index(rdbx, guess, s)
michael@0 312 *
michael@0 313 * given an rdbx and a sequence number s (from a newly arrived packet),
michael@0 314 * sets the contents of *guess to contain the best guess of the packet
michael@0 315 * index to which s corresponds, and returns the difference between
michael@0 316 * *guess and the locally stored synch info
michael@0 317 */
michael@0 318
michael@0 319 int
michael@0 320 rdbx_estimate_index(const rdbx_t *rdbx,
michael@0 321 xtd_seq_num_t *guess,
michael@0 322 sequence_number_t s) {
michael@0 323
michael@0 324 /*
michael@0 325 * if the sequence number and rollover counter in the rdbx are
michael@0 326 * non-zero, then use the index_guess(...) function, otherwise, just
michael@0 327 * set the rollover counter to zero (since the index_guess(...)
michael@0 328 * function might incorrectly guess that the rollover counter is
michael@0 329 * 0xffffffff)
michael@0 330 */
michael@0 331
michael@0 332 #ifdef NO_64BIT_MATH
michael@0 333 /* seq_num_median = 0x8000 */
michael@0 334 if (high32(rdbx->index) > 0 ||
michael@0 335 low32(rdbx->index) > seq_num_median)
michael@0 336 #else
michael@0 337 if (rdbx->index > seq_num_median)
michael@0 338 #endif
michael@0 339 return index_guess(&rdbx->index, guess, s);
michael@0 340
michael@0 341 #ifdef NO_64BIT_MATH
michael@0 342 *guess = make64(0,(uint32_t) s);
michael@0 343 #else
michael@0 344 *guess = s;
michael@0 345 #endif
michael@0 346
michael@0 347 #ifdef NO_64BIT_MATH
michael@0 348 return s - (uint16_t) low32(rdbx->index);
michael@0 349 #else
michael@0 350 return s - (uint16_t) rdbx->index;
michael@0 351 #endif
michael@0 352 }

mercurial