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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/srtp/src/crypto/replay/rdbx.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,352 @@
     1.4 +/*
     1.5 + * rdbx.c
     1.6 + *
     1.7 + * a replay database with extended range, using a rollover counter
     1.8 + *
     1.9 + * David A. McGrew
    1.10 + * Cisco Systems, Inc.
    1.11 + */
    1.12 +
    1.13 +/*
    1.14 + *	
    1.15 + * Copyright (c) 2001-2006, Cisco Systems, Inc.
    1.16 + * All rights reserved.
    1.17 + * 
    1.18 + * Redistribution and use in source and binary forms, with or without
    1.19 + * modification, are permitted provided that the following conditions
    1.20 + * are met:
    1.21 + * 
    1.22 + *   Redistributions of source code must retain the above copyright
    1.23 + *   notice, this list of conditions and the following disclaimer.
    1.24 + * 
    1.25 + *   Redistributions in binary form must reproduce the above
    1.26 + *   copyright notice, this list of conditions and the following
    1.27 + *   disclaimer in the documentation and/or other materials provided
    1.28 + *   with the distribution.
    1.29 + * 
    1.30 + *   Neither the name of the Cisco Systems, Inc. nor the names of its
    1.31 + *   contributors may be used to endorse or promote products derived
    1.32 + *   from this software without specific prior written permission.
    1.33 + * 
    1.34 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.35 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.36 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    1.37 + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    1.38 + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    1.39 + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    1.40 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    1.41 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    1.42 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    1.43 + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    1.44 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
    1.45 + * OF THE POSSIBILITY OF SUCH DAMAGE.
    1.46 + *
    1.47 + */
    1.48 +
    1.49 +#include "rdbx.h"
    1.50 +
    1.51 +
    1.52 +/*
    1.53 + * from RFC 3711:
    1.54 + *
    1.55 + * A receiver reconstructs the index i of a packet with sequence
    1.56 + *  number SEQ using the estimate
    1.57 + *
    1.58 + * i = 2^16 * v + SEQ,
    1.59 + *
    1.60 + * where v is chosen from the set { ROC-1, ROC, ROC+1 } such that i is
    1.61 + * closest to the value 2^16 * ROC + s_l.  If the value r+1 is used,
    1.62 + * then the rollover counter r in the cryptographic context is
    1.63 + * incremented by one (if the packet containing s is authentic).
    1.64 + */
    1.65 +
    1.66 +
    1.67 +
    1.68 +/*
    1.69 + * rdbx implementation notes
    1.70 + *
    1.71 + * A xtd_seq_num_t is essentially a sequence number for which some of
    1.72 + * the data on the wire are implicit.  It logically consists of a
    1.73 + * rollover counter and a sequence number; the sequence number is the
    1.74 + * explicit part, and the rollover counter is the implicit part.
    1.75 + *
    1.76 + * Upon receiving a sequence_number (e.g. in a newly received SRTP
    1.77 + * packet), the complete xtd_seq_num_t can be estimated by using a
    1.78 + * local xtd_seq_num_t as a basis.  This is done using the function
    1.79 + * index_guess(&local, &guess, seq_from_packet).  This function
    1.80 + * returns the difference of the guess and the local value.  The local
    1.81 + * xtd_seq_num_t can be moved forward to the guess using the function
    1.82 + * index_advance(&guess, delta), where delta is the difference.
    1.83 + * 
    1.84 + *
    1.85 + * A rdbx_t consists of a xtd_seq_num_t and a bitmask.  The index is highest
    1.86 + * sequence number that has been received, and the bitmask indicates
    1.87 + * which of the recent indicies have been received as well.  The
    1.88 + * highest bit in the bitmask corresponds to the index in the bitmask.
    1.89 + */
    1.90 +
    1.91 +
    1.92 +void
    1.93 +index_init(xtd_seq_num_t *pi) {
    1.94 +#ifdef NO_64BIT_MATH
    1.95 +  *pi = make64(0,0);
    1.96 +#else
    1.97 +  *pi = 0;
    1.98 +#endif
    1.99 +}
   1.100 +
   1.101 +void
   1.102 +index_advance(xtd_seq_num_t *pi, sequence_number_t s) {
   1.103 +#ifdef NO_64BIT_MATH
   1.104 +  /* a > ~b means a+b will generate a carry */
   1.105 +  /* s is uint16 here */
   1.106 +  *pi = make64(high32(*pi) + (s > ~low32(*pi) ? 1 : 0),low32(*pi) + s);
   1.107 +#else
   1.108 +  *pi += s;
   1.109 +#endif
   1.110 +}
   1.111 +
   1.112 +
   1.113 +/*
   1.114 + * index_guess(local, guess, s)
   1.115 + * 
   1.116 + * given a xtd_seq_num_t local (which represents the last
   1.117 + * known-to-be-good received xtd_seq_num_t) and a sequence number s
   1.118 + * (from a newly arrived packet), sets the contents of *guess to
   1.119 + * contain the best guess of the packet index to which s corresponds,
   1.120 + * and returns the difference between *guess and *local
   1.121 + *
   1.122 + * nota bene - the output is a signed integer, DON'T cast it to a
   1.123 + * unsigned integer!  
   1.124 + */
   1.125 +
   1.126 +int
   1.127 +index_guess(const xtd_seq_num_t *local,
   1.128 +		   xtd_seq_num_t *guess,
   1.129 +		   sequence_number_t s) {
   1.130 +#ifdef NO_64BIT_MATH
   1.131 +  uint32_t local_roc = ((high32(*local) << 16) |
   1.132 +						(low32(*local) >> 16));
   1.133 +  uint16_t local_seq = (uint16_t) (low32(*local));
   1.134 +#else
   1.135 +  uint32_t local_roc = (uint32_t)(*local >> 16);
   1.136 +  uint16_t local_seq = (uint16_t) *local;
   1.137 +#endif
   1.138 +#ifdef NO_64BIT_MATH
   1.139 +  uint32_t guess_roc = ((high32(*guess) << 16) |
   1.140 +						(low32(*guess) >> 16));
   1.141 +  uint16_t guess_seq = (uint16_t) (low32(*guess));
   1.142 +#else
   1.143 +  uint32_t guess_roc = (uint32_t)(*guess >> 16);
   1.144 +  uint16_t guess_seq = (uint16_t) *guess;  
   1.145 +#endif
   1.146 +  int difference;
   1.147 +  
   1.148 +  if (local_seq < seq_num_median) {
   1.149 +    if (s - local_seq > seq_num_median) {
   1.150 +      guess_roc = local_roc - 1;
   1.151 +      difference = seq_num_max - s + local_seq;
   1.152 +    } else {
   1.153 +      guess_roc = local_roc;
   1.154 +      difference = s - local_seq;
   1.155 +    }
   1.156 +  } else {
   1.157 +    if (local_seq - seq_num_median > s) {
   1.158 +      guess_roc = local_roc+1;
   1.159 +      difference = seq_num_max - local_seq + s;
   1.160 +    } else {
   1.161 +      difference = s - local_seq;
   1.162 +      guess_roc = local_roc;
   1.163 +    }
   1.164 +  }
   1.165 +  guess_seq = s;
   1.166 +  
   1.167 +  /* Note: guess_roc is 32 bits, so this generates a 48-bit result! */
   1.168 +#ifdef NO_64BIT_MATH
   1.169 +  *guess = make64(guess_roc >> 16,
   1.170 +				  (guess_roc << 16) | guess_seq);
   1.171 +#else
   1.172 +  *guess = (((uint64_t) guess_roc) << 16) | guess_seq;
   1.173 +#endif
   1.174 +
   1.175 +  return difference;
   1.176 +}
   1.177 +
   1.178 +/*
   1.179 + * rdbx
   1.180 + *
   1.181 + */
   1.182 +
   1.183 +
   1.184 +/*
   1.185 + *  rdbx_init(&r, ws) initializes the rdbx_t pointed to by r with window size ws
   1.186 + */
   1.187 +
   1.188 +err_status_t
   1.189 +rdbx_init(rdbx_t *rdbx, unsigned long ws) {
   1.190 +  if (ws == 0)
   1.191 +    return err_status_bad_param;
   1.192 +
   1.193 +  if (bitvector_alloc(&rdbx->bitmask, ws) != 0)
   1.194 +    return err_status_alloc_fail;
   1.195 +
   1.196 +  index_init(&rdbx->index);
   1.197 +
   1.198 +  return err_status_ok;
   1.199 +}
   1.200 +
   1.201 +/*
   1.202 + *  rdbx_dealloc(&r) frees memory for the rdbx_t pointed to by r
   1.203 + */
   1.204 +
   1.205 +err_status_t
   1.206 +rdbx_dealloc(rdbx_t *rdbx) {
   1.207 +  bitvector_dealloc(&rdbx->bitmask);
   1.208 +
   1.209 +  return err_status_ok;
   1.210 +}
   1.211 +
   1.212 +/*
   1.213 + * rdbx_set_roc(rdbx, roc) initalizes the rdbx_t at the location rdbx
   1.214 + * to have the rollover counter value roc.  If that value is less than
   1.215 + * the current rollover counter value, then the function returns
   1.216 + * err_status_replay_old; otherwise, err_status_ok is returned.
   1.217 + * 
   1.218 + */
   1.219 +
   1.220 +err_status_t
   1.221 +rdbx_set_roc(rdbx_t *rdbx, uint32_t roc) {
   1.222 +  bitvector_set_to_zero(&rdbx->bitmask);
   1.223 +
   1.224 +#ifdef NO_64BIT_MATH
   1.225 +  #error not yet implemented
   1.226 +#else
   1.227 +
   1.228 +  /* make sure that we're not moving backwards */
   1.229 +  if (roc < (rdbx->index >> 16))
   1.230 +    return err_status_replay_old;
   1.231 +
   1.232 +  rdbx->index &= 0xffff;   /* retain lowest 16 bits */
   1.233 +  rdbx->index |= ((uint64_t)roc) << 16;  /* set ROC */
   1.234 +#endif
   1.235 +
   1.236 +  return err_status_ok;
   1.237 +}
   1.238 +
   1.239 +/*
   1.240 + * rdbx_get_packet_index(rdbx) returns the value of the packet index
   1.241 + * for the rdbx_t pointed to by rdbx
   1.242 + * 
   1.243 + */
   1.244 +
   1.245 +xtd_seq_num_t
   1.246 +rdbx_get_packet_index(const rdbx_t *rdbx) {
   1.247 +  return rdbx->index;   
   1.248 +}
   1.249 +
   1.250 +/*
   1.251 + * rdbx_get_window_size(rdbx) returns the value of the window size
   1.252 + * for the rdbx_t pointed to by rdbx
   1.253 + * 
   1.254 + */
   1.255 +
   1.256 +unsigned long
   1.257 +rdbx_get_window_size(const rdbx_t *rdbx) {
   1.258 +  return bitvector_get_length(&rdbx->bitmask);
   1.259 +}
   1.260 +
   1.261 +/*
   1.262 + * rdbx_check(&r, delta) checks to see if the xtd_seq_num_t
   1.263 + * which is at rdbx->index + delta is in the rdb
   1.264 + */
   1.265 +
   1.266 +err_status_t
   1.267 +rdbx_check(const rdbx_t *rdbx, int delta) {
   1.268 +  
   1.269 +  if (delta > 0) {       /* if delta is positive, it's good */
   1.270 +    return err_status_ok;
   1.271 +  } else if ((int)(bitvector_get_length(&rdbx->bitmask) - 1) + delta < 0) {   
   1.272 +                         /* if delta is lower than the bitmask, it's bad */
   1.273 +    return err_status_replay_old; 
   1.274 +  } else if (bitvector_get_bit(&rdbx->bitmask, 
   1.275 +			       (int)(bitvector_get_length(&rdbx->bitmask) - 1) + delta) == 1) {
   1.276 +                         /* delta is within the window, so check the bitmask */
   1.277 +    return err_status_replay_fail;    
   1.278 +  }
   1.279 + /* otherwise, the index is okay */
   1.280 +
   1.281 +  return err_status_ok; 
   1.282 +}
   1.283 +
   1.284 +/*
   1.285 + * rdbx_add_index adds the xtd_seq_num_t at rdbx->window_start + d to
   1.286 + * replay_db (and does *not* check if that xtd_seq_num_t appears in db)
   1.287 + *
   1.288 + * this function should be called only after replay_check has
   1.289 + * indicated that the index does not appear in the rdbx, e.g., a mutex
   1.290 + * should protect the rdbx between these calls if need be
   1.291 + */
   1.292 +
   1.293 +err_status_t
   1.294 +rdbx_add_index(rdbx_t *rdbx, int delta) {
   1.295 +  
   1.296 +  if (delta > 0) {
   1.297 +    /* shift forward by delta */
   1.298 +    index_advance(&rdbx->index, delta);
   1.299 +    bitvector_left_shift(&rdbx->bitmask, delta);
   1.300 +    bitvector_set_bit(&rdbx->bitmask, bitvector_get_length(&rdbx->bitmask) - 1);
   1.301 +  } else {
   1.302 +    /* delta is in window */
   1.303 +    bitvector_set_bit(&rdbx->bitmask, bitvector_get_length(&rdbx->bitmask) -1 + delta);
   1.304 +  }
   1.305 +
   1.306 +  /* note that we need not consider the case that delta == 0 */
   1.307 +  
   1.308 +  return err_status_ok;
   1.309 +}
   1.310 +
   1.311 +
   1.312 +
   1.313 +/*
   1.314 + * rdbx_estimate_index(rdbx, guess, s)
   1.315 + * 
   1.316 + * given an rdbx and a sequence number s (from a newly arrived packet),
   1.317 + * sets the contents of *guess to contain the best guess of the packet
   1.318 + * index to which s corresponds, and returns the difference between
   1.319 + * *guess and the locally stored synch info
   1.320 + */
   1.321 +
   1.322 +int
   1.323 +rdbx_estimate_index(const rdbx_t *rdbx,
   1.324 +		    xtd_seq_num_t *guess,
   1.325 +		    sequence_number_t s) {
   1.326 +
   1.327 +  /*
   1.328 +   * if the sequence number and rollover counter in the rdbx are
   1.329 +   * non-zero, then use the index_guess(...) function, otherwise, just
   1.330 +   * set the rollover counter to zero (since the index_guess(...)
   1.331 +   * function might incorrectly guess that the rollover counter is
   1.332 +   * 0xffffffff)
   1.333 +   */
   1.334 +
   1.335 +#ifdef NO_64BIT_MATH
   1.336 +  /* seq_num_median = 0x8000 */
   1.337 +  if (high32(rdbx->index) > 0 ||
   1.338 +	  low32(rdbx->index) > seq_num_median)
   1.339 +#else
   1.340 +  if (rdbx->index > seq_num_median)
   1.341 +#endif
   1.342 +    return index_guess(&rdbx->index, guess, s);
   1.343 +  
   1.344 +#ifdef NO_64BIT_MATH
   1.345 +  *guess = make64(0,(uint32_t) s);
   1.346 +#else  
   1.347 +  *guess = s;
   1.348 +#endif
   1.349 +
   1.350 +#ifdef NO_64BIT_MATH
   1.351 +  return s - (uint16_t) low32(rdbx->index);
   1.352 +#else
   1.353 +  return s - (uint16_t) rdbx->index;
   1.354 +#endif
   1.355 +}

mercurial