1 /**
2 * TLS Sequence Number Handling
3 * 
4 * Copyright:
5 * (C) 2012 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.tls.seq_numbers;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_TLS):
15 package:
16 
17 import botan.utils.types;
18 import std.exception;
19 import memutils.hashmap;
20 
21 
22 interface ConnectionSequenceNumbers
23 {
24 public:
25     abstract void newReadCipherState();
26     abstract void newWriteCipherState();
27 
28     abstract ushort currentReadEpoch() const;
29     abstract ushort currentWriteEpoch() const;
30 
31     abstract ulong nextWriteSequence(ushort);
32     abstract ulong nextReadSequence();
33 
34     abstract bool alreadySeen(ulong seq) const;
35     abstract void readAccept(ulong seq);
36 }
37 
38 final class StreamSequenceNumbers : ConnectionSequenceNumbers
39 {
40 public:
41     override void newReadCipherState() { m_read_seq_no = 0; m_read_epoch += 1; }
42     override void newWriteCipherState() { m_write_seq_no = 0; m_write_epoch += 1; }
43 
44     override ushort currentReadEpoch() const { return m_read_epoch; }
45     override ushort currentWriteEpoch() const { return m_write_epoch; }
46 
47     override ulong nextWriteSequence(ushort) { return m_write_seq_no++; }
48     override ulong nextReadSequence() { return m_read_seq_no; }
49 
50     override bool alreadySeen(ulong) const { return false; }
51     override void readAccept(ulong) { m_read_seq_no++; }
52 private:
53     ulong m_write_seq_no = 0;
54     ulong m_read_seq_no = 0;
55     ushort m_read_epoch = 0;
56     ushort m_write_epoch = 0;
57 }
58 
59 final class DatagramSequenceNumbers : ConnectionSequenceNumbers
60 {
61 public:
62     this() { m_write_seqs[0] = 0; }
63 
64     override void newReadCipherState() { m_read_epoch += 1; }
65 
66     override void newWriteCipherState()
67     {
68         m_write_epoch += 1;
69         m_write_seqs[m_write_epoch] = 0;
70     }
71 
72     override ushort currentReadEpoch() const { return m_read_epoch; }
73     override ushort currentWriteEpoch() const { return m_write_epoch; }
74 
75     override ulong nextWriteSequence(ushort epoch) 
76     { 
77         ulong* i = epoch in m_write_seqs;
78         assert(i !is null, "Found epoch");
79         return ((cast(ulong) epoch) << 48 ) | ((*i)++);
80     }
81 
82     override ulong nextReadSequence()
83     {
84         throw new Exception("DTLS uses explicit sequence numbers");
85     }
86 
87     override bool alreadySeen(ulong sequence) const
88     {
89         const size_t window_size = (m_window_bits).sizeof * 8;
90 
91         if (sequence > m_window_highest)
92             return false;
93 
94         const ulong offset = m_window_highest - sequence;
95 
96         if (offset >= window_size)
97             return true; // really old?
98 
99         return (((m_window_bits >> offset) & 1) == 1);
100     }
101 
102     override void readAccept(ulong sequence)
103     {
104         const size_t window_size = (m_window_bits).sizeof * 8;
105 
106         if (sequence > m_window_highest)
107         {
108             const size_t offset = cast(size_t)(sequence - m_window_highest);
109             m_window_highest += offset;
110 
111             if (offset >= window_size)
112                 m_window_bits = 0;
113             else
114                 m_window_bits <<= offset;
115 
116             m_window_bits |= 0x01;
117         }
118         else
119         {
120             const ulong offset = m_window_highest - sequence;
121             m_window_bits |= (cast(ulong)(1) << offset);
122         }
123     }
124 
125 private:
126     HashMap!(ushort, ulong) m_write_seqs;
127     ushort m_write_epoch;
128     ushort m_read_epoch;
129     ulong m_window_highest;
130     ulong m_window_bits;
131 }