1 /*
2 * SecureQueue
3 * (C) 1999-2007 Jack Lloyd
4 * 2012 Markus Wanner
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8
9 #include <botan/secqueue.h>
10 #include <algorithm>
11
12 namespace Botan {
13
14 /**
15 * A node in a SecureQueue
16 */
17 class SecureQueueNode final
18 {
19 public:
SecureQueueNode()20 SecureQueueNode() : m_buffer(BOTAN_DEFAULT_BUFFER_SIZE)
21 { m_next = nullptr; m_start = m_end = 0; }
22
~SecureQueueNode()23 ~SecureQueueNode() { m_next = nullptr; m_start = m_end = 0; }
24
write(const uint8_t input[],size_t length)25 size_t write(const uint8_t input[], size_t length)
26 {
27 size_t copied = std::min<size_t>(length, m_buffer.size() - m_end);
28 copy_mem(m_buffer.data() + m_end, input, copied);
29 m_end += copied;
30 return copied;
31 }
32
read(uint8_t output[],size_t length)33 size_t read(uint8_t output[], size_t length)
34 {
35 size_t copied = std::min(length, m_end - m_start);
36 copy_mem(output, m_buffer.data() + m_start, copied);
37 m_start += copied;
38 return copied;
39 }
40
peek(uint8_t output[],size_t length,size_t offset=0)41 size_t peek(uint8_t output[], size_t length, size_t offset = 0)
42 {
43 const size_t left = m_end - m_start;
44 if(offset >= left) return 0;
45 size_t copied = std::min(length, left - offset);
46 copy_mem(output, m_buffer.data() + m_start + offset, copied);
47 return copied;
48 }
49
size() const50 size_t size() const { return (m_end - m_start); }
51 private:
52 friend class SecureQueue;
53 SecureQueueNode* m_next;
54 secure_vector<uint8_t> m_buffer;
55 size_t m_start, m_end;
56 };
57
58 /*
59 * Create a SecureQueue
60 */
SecureQueue()61 SecureQueue::SecureQueue()
62 {
63 m_bytes_read = 0;
64 set_next(nullptr, 0);
65 m_head = m_tail = new SecureQueueNode;
66 }
67
68 /*
69 * Copy a SecureQueue
70 */
SecureQueue(const SecureQueue & input)71 SecureQueue::SecureQueue(const SecureQueue& input) :
72 Fanout_Filter(), DataSource()
73 {
74 m_bytes_read = 0;
75 set_next(nullptr, 0);
76
77 m_head = m_tail = new SecureQueueNode;
78 SecureQueueNode* temp = input.m_head;
79 while(temp)
80 {
81 write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start);
82 temp = temp->m_next;
83 }
84 }
85
86 /*
87 * Destroy this SecureQueue
88 */
destroy()89 void SecureQueue::destroy()
90 {
91 SecureQueueNode* temp = m_head;
92 while(temp)
93 {
94 SecureQueueNode* holder = temp->m_next;
95 delete temp;
96 temp = holder;
97 }
98 m_head = m_tail = nullptr;
99 }
100
101 /*
102 * Copy a SecureQueue
103 */
operator =(const SecureQueue & input)104 SecureQueue& SecureQueue::operator=(const SecureQueue& input)
105 {
106 if(this == &input)
107 return *this;
108
109 destroy();
110 m_bytes_read = input.get_bytes_read();
111 m_head = m_tail = new SecureQueueNode;
112 SecureQueueNode* temp = input.m_head;
113 while(temp)
114 {
115 write(&temp->m_buffer[temp->m_start], temp->m_end - temp->m_start);
116 temp = temp->m_next;
117 }
118 return (*this);
119 }
120
121 /*
122 * Add some bytes to the queue
123 */
write(const uint8_t input[],size_t length)124 void SecureQueue::write(const uint8_t input[], size_t length)
125 {
126 if(!m_head)
127 m_head = m_tail = new SecureQueueNode;
128 while(length)
129 {
130 const size_t n = m_tail->write(input, length);
131 input += n;
132 length -= n;
133 if(length)
134 {
135 m_tail->m_next = new SecureQueueNode;
136 m_tail = m_tail->m_next;
137 }
138 }
139 }
140
141 /*
142 * Read some bytes from the queue
143 */
read(uint8_t output[],size_t length)144 size_t SecureQueue::read(uint8_t output[], size_t length)
145 {
146 size_t got = 0;
147 while(length && m_head)
148 {
149 const size_t n = m_head->read(output, length);
150 output += n;
151 got += n;
152 length -= n;
153 if(m_head->size() == 0)
154 {
155 SecureQueueNode* holder = m_head->m_next;
156 delete m_head;
157 m_head = holder;
158 }
159 }
160 m_bytes_read += got;
161 return got;
162 }
163
164 /*
165 * Read data, but do not remove it from queue
166 */
peek(uint8_t output[],size_t length,size_t offset) const167 size_t SecureQueue::peek(uint8_t output[], size_t length, size_t offset) const
168 {
169 SecureQueueNode* current = m_head;
170
171 while(offset && current)
172 {
173 if(offset >= current->size())
174 {
175 offset -= current->size();
176 current = current->m_next;
177 }
178 else
179 break;
180 }
181
182 size_t got = 0;
183 while(length && current)
184 {
185 const size_t n = current->peek(output, length, offset);
186 offset = 0;
187 output += n;
188 got += n;
189 length -= n;
190 current = current->m_next;
191 }
192 return got;
193 }
194
195 /**
196 * Return how many bytes have been read so far.
197 */
get_bytes_read() const198 size_t SecureQueue::get_bytes_read() const
199 {
200 return m_bytes_read;
201 }
202
203 /*
204 * Return how many bytes the queue holds
205 */
size() const206 size_t SecureQueue::size() const
207 {
208 SecureQueueNode* current = m_head;
209 size_t count = 0;
210
211 while(current)
212 {
213 count += current->size();
214 current = current->m_next;
215 }
216 return count;
217 }
218
219 /*
220 * Test if the queue has any data in it
221 */
end_of_data() const222 bool SecureQueue::end_of_data() const
223 {
224 return (size() == 0);
225 }
226
empty() const227 bool SecureQueue::empty() const
228 {
229 return (size() == 0);
230 }
231
232 }
233