9dae9b273e60a831123ad9a0047a66b8cc542358
[openssl.git] / ssl / record / dtls1_bitmap.c
1 /*
2  * Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "../ssl_locl.h"
11 #include "record_locl.h"
12
13 /* mod 128 saturating subtract of two 64-bit values in big-endian order */
14 static int satsub64be(const unsigned char *v1, const unsigned char *v2)
15 {
16     int ret, sat, brw, i;
17
18     if (sizeof(long) == 8)
19         do {
20             const union {
21                 long one;
22                 char little;
23             } is_endian = {
24                 1
25             };
26             long l;
27
28             if (is_endian.little)
29                 break;
30             /* not reached on little-endians */
31             /*
32              * following test is redundant, because input is always aligned,
33              * but I take no chances...
34              */
35             if (((size_t)v1 | (size_t)v2) & 0x7)
36                 break;
37
38             l = *((long *)v1);
39             l -= *((long *)v2);
40             if (l > 128)
41                 return 128;
42             else if (l < -128)
43                 return -128;
44             else
45                 return (int)l;
46         } while (0);
47
48     ret = (int)v1[7] - (int)v2[7];
49     sat = 0;
50     brw = ret >> 8;             /* brw is either 0 or -1 */
51     if (ret & 0x80) {
52         for (i = 6; i >= 0; i--) {
53             brw += (int)v1[i] - (int)v2[i];
54             sat |= ~brw;
55             brw >>= 8;
56         }
57     } else {
58         for (i = 6; i >= 0; i--) {
59             brw += (int)v1[i] - (int)v2[i];
60             sat |= brw;
61             brw >>= 8;
62         }
63     }
64     brw <<= 8;                  /* brw is either 0 or -256 */
65
66     if (sat & 0xff)
67         return brw | 0x80;
68     else
69         return brw + (ret & 0xFF);
70 }
71
72 int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap)
73 {
74     int cmp;
75     unsigned int shift;
76     const unsigned char *seq = s->rlayer.read_sequence;
77
78     cmp = satsub64be(seq, bitmap->max_seq_num);
79     if (cmp > 0) {
80         SSL3_RECORD_set_seq_num(RECORD_LAYER_get_rrec(&s->rlayer), seq);
81         return 1;               /* this record in new */
82     }
83     shift = -cmp;
84     if (shift >= sizeof(bitmap->map) * 8)
85         return 0;               /* stale, outside the window */
86     else if (bitmap->map & (1UL << shift))
87         return 0;               /* record previously received */
88
89     SSL3_RECORD_set_seq_num(RECORD_LAYER_get_rrec(&s->rlayer), seq);
90     return 1;
91 }
92
93 void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap)
94 {
95     int cmp;
96     unsigned int shift;
97     const unsigned char *seq = RECORD_LAYER_get_read_sequence(&s->rlayer);
98
99     cmp = satsub64be(seq, bitmap->max_seq_num);
100     if (cmp > 0) {
101         shift = cmp;
102         if (shift < sizeof(bitmap->map) * 8)
103             bitmap->map <<= shift, bitmap->map |= 1UL;
104         else
105             bitmap->map = 1UL;
106         memcpy(bitmap->max_seq_num, seq, SEQ_NUM_SIZE);
107     } else {
108         shift = -cmp;
109         if (shift < sizeof(bitmap->map) * 8)
110             bitmap->map |= 1UL << shift;
111     }
112 }