aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/tls/tls_seq_numbers.h
blob: d7b8c919c78eff844097f60b0115dbabff34ed51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
* TLS Sequence Number Handling
* (C) 2012 Jack Lloyd
*
* Released under the terms of the Botan license
*/

#ifndef BOTAN_TLS_SEQ_NUMBERS_H__
#define BOTAN_TLS_SEQ_NUMBERS_H__

#include <botan/types.h>
#include <stdexcept>

namespace Botan {

namespace TLS {

class Connection_Sequence_Numbers
   {
   public:
      virtual void new_read_cipher_state() = 0;
      virtual void new_write_cipher_state() = 0;

      virtual u16bit current_read_epoch() const = 0;
      virtual u16bit current_write_epoch() const = 0;

      virtual u64bit next_write_sequence(u16bit) = 0;
      virtual u64bit next_read_sequence() = 0;

      virtual bool already_seen(u64bit seq) const = 0;
      virtual void read_accept(u64bit seq) = 0;
   };

class Stream_Sequence_Numbers : public Connection_Sequence_Numbers
   {
   public:
      void new_read_cipher_state() override { m_read_seq_no = 0; m_read_epoch += 1; }
      void new_write_cipher_state() override { m_write_seq_no = 0; m_write_epoch += 1; }

      u16bit current_read_epoch() const override { return m_read_epoch; }
      u16bit current_write_epoch() const override { return m_write_epoch; }

      u64bit next_write_sequence(u16bit) override { return m_write_seq_no++; }
      u64bit next_read_sequence() override { return m_read_seq_no; }

      bool already_seen(u64bit) const override { return false; }
      void read_accept(u64bit) override { m_read_seq_no++; }
   private:
      u64bit m_write_seq_no = 0;
      u64bit m_read_seq_no = 0;
      u16bit m_read_epoch = 0;
      u16bit m_write_epoch = 0;
   };

class Datagram_Sequence_Numbers : public Connection_Sequence_Numbers
   {
   public:
      Datagram_Sequence_Numbers() { m_write_seqs[0] = 0; }

      void new_read_cipher_state() override { m_read_epoch += 1; }

      void new_write_cipher_state() override
         {
         m_write_epoch += 1;
         m_write_seqs[m_write_epoch] = 0;
         }

      u16bit current_read_epoch() const override { return m_read_epoch; }
      u16bit current_write_epoch() const override { return m_write_epoch; }

      u64bit next_write_sequence(u16bit epoch) override
         {
         auto i = m_write_seqs.find(epoch);
         BOTAN_ASSERT(i != m_write_seqs.end(), "Found epoch");
         return (static_cast<u64bit>(epoch) << 48) | i->second++;
         }

      u64bit next_read_sequence() override
         {
         throw std::runtime_error("DTLS uses explicit sequence numbers");
         }

      bool already_seen(u64bit sequence) const override
         {
         const size_t window_size = sizeof(m_window_bits) * 8;

         if(sequence > m_window_highest)
            return false;

         const u64bit offset = m_window_highest - sequence;

         if(offset >= window_size)
            return true; // really old?

         return (((m_window_bits >> offset) & 1) == 1);
         }

      void read_accept(u64bit sequence) override
         {
         const size_t window_size = sizeof(m_window_bits) * 8;

         if(sequence > m_window_highest)
            {
            const size_t offset = sequence - m_window_highest;
            m_window_highest += offset;

            if(offset >= window_size)
               m_window_bits = 0;
            else
               m_window_bits <<= offset;

            m_window_bits |= 0x01;
            }
         else
            {
            const u64bit offset = m_window_highest - sequence;
            m_window_bits |= (static_cast<u64bit>(1) << offset);
            }
         }

   private:
      std::map<u16bit, u64bit> m_write_seqs;
      u16bit m_write_epoch = 0;
      u16bit m_read_epoch = 0;
      u64bit m_window_highest = 0;
      u64bit m_window_bits = 0;
   };

}

}

#endif