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 }