tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

rdbx.c (11699B)


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