BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file OTPChecker.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <string.h>
31  
32 #include <misc/balloc.h>
33  
34 #include <security/OTPChecker.h>
35  
36 static void OTPChecker_Table_Empty (OTPChecker *mc, struct OTPChecker_table *t);
37 static void OTPChecker_Table_AddOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp);
38 static void OTPChecker_Table_Generate (OTPChecker *mc, struct OTPChecker_table *t, OTPCalculator *calc, uint8_t *key, uint8_t *iv);
39 static int OTPChecker_Table_CheckOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp);
40  
41 void OTPChecker_Table_Empty (OTPChecker *mc, struct OTPChecker_table *t)
42 {
43 for (int i = 0; i < mc->num_entries; i++) {
44 t->entries[i].avail = -1;
45 }
46 }
47  
48 void OTPChecker_Table_AddOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp)
49 {
50 // calculate starting index
51 int start_index = otp % mc->num_entries;
52  
53 // try indexes starting with the base position
54 for (int i = 0; i < mc->num_entries; i++) {
55 int index = bmodadd_int(start_index, i, mc->num_entries);
56 struct OTPChecker_entry *entry = &t->entries[index];
57  
58 // if we find a free index, use it
59 if (entry->avail < 0) {
60 entry->otp = otp;
61 entry->avail = 1;
62 return;
63 }
64  
65 // if we find a used index with the same mac,
66 // use it by incrementing its count
67 if (entry->otp == otp) {
68 entry->avail++;
69 return;
70 }
71 }
72  
73 // will never add more macs than we can hold
74 ASSERT(0)
75 }
76  
77 void OTPChecker_Table_Generate (OTPChecker *mc, struct OTPChecker_table *t, OTPCalculator *calc, uint8_t *key, uint8_t *iv)
78 {
79 // calculate values
80 otp_t *otps = OTPCalculator_Generate(calc, key, iv, 0);
81  
82 // empty table
83 OTPChecker_Table_Empty(mc ,t);
84  
85 // add calculated values to table
86 for (int i = 0; i < mc->num_otps; i++) {
87 OTPChecker_Table_AddOTP(mc, t, otps[i]);
88 }
89 }
90  
91 int OTPChecker_Table_CheckOTP (OTPChecker *mc, struct OTPChecker_table *t, otp_t otp)
92 {
93 // calculate starting index
94 int start_index = otp % mc->num_entries;
95  
96 // try indexes starting with the base position
97 for (int i = 0; i < mc->num_entries; i++) {
98 int index = bmodadd_int(start_index, i, mc->num_entries);
99 struct OTPChecker_entry *entry = &t->entries[index];
100  
101 // if we find an empty entry, there is no such mac
102 if (entry->avail < 0) {
103 return 0;
104 }
105  
106 // if we find a matching entry, check its count
107 if (entry->otp == otp) {
108 if (entry->avail > 0) {
109 entry->avail--;
110 return 1;
111 }
112 return 0;
113 }
114 }
115  
116 // there are always empty slots
117 ASSERT(0)
118 return 0;
119 }
120  
121 static void work_func (OTPChecker *mc)
122 {
123 struct OTPChecker_table *table = &mc->tables[mc->next_table];
124 OTPChecker_Table_Generate(mc, table, &mc->calc, mc->tw_key, mc->tw_iv);
125 }
126  
127 static void work_done_handler (OTPChecker *mc)
128 {
129 ASSERT(mc->tw_have)
130 DebugObject_Access(&mc->d_obj);
131  
132 // free work
133 BThreadWork_Free(&mc->tw);
134 mc->tw_have = 0;
135  
136 // update next table number
137 mc->next_table = bmodadd_int(mc->next_table, 1, mc->num_tables);
138  
139 // update number of used tables if not all are used yet
140 if (mc->tables_used < mc->num_tables) {
141 mc->tables_used++;
142 }
143  
144 // call handler
145 if (mc->handler) {
146 mc->handler(mc->user);
147 return;
148 }
149 }
150  
151 int OTPChecker_Init (OTPChecker *mc, int num_otps, int cipher, int num_tables, BThreadWorkDispatcher *twd)
152 {
153 ASSERT(num_otps > 0)
154 ASSERT(BEncryption_cipher_valid(cipher))
155 ASSERT(num_tables > 0)
156  
157 // init arguments
158 mc->num_otps = num_otps;
159 mc->cipher = cipher;
160 mc->num_tables = num_tables;
161 mc->twd = twd;
162  
163 // set no handlers
164 mc->handler = NULL;
165  
166 // set number of entries
167 if (mc->num_otps > INT_MAX / 2) {
168 goto fail0;
169 }
170 mc->num_entries = 2 * mc->num_otps;
171  
172 // set no tables used
173 mc->tables_used = 0;
174 mc->next_table = 0;
175  
176 // initialize calculator
177 if (!OTPCalculator_Init(&mc->calc, mc->num_otps, cipher)) {
178 goto fail0;
179 }
180  
181 // allocate tables
182 if (!(mc->tables = (struct OTPChecker_table *)BAllocArray(mc->num_tables, sizeof(mc->tables[0])))) {
183 goto fail1;
184 }
185  
186 // allocate entries
187 if (!(mc->entries = (struct OTPChecker_entry *)BAllocArray2(mc->num_tables, mc->num_entries, sizeof(mc->entries[0])))) {
188 goto fail2;
189 }
190  
191 // initialize tables
192 for (int i = 0; i < mc->num_tables; i++) {
193 struct OTPChecker_table *table = &mc->tables[i];
194 table->entries = mc->entries + (size_t)i * mc->num_entries;
195 OTPChecker_Table_Empty(mc, table);
196 }
197  
198 // have no work
199 mc->tw_have = 0;
200  
201 DebugObject_Init(&mc->d_obj);
202 return 1;
203  
204 fail2:
205 BFree(mc->tables);
206 fail1:
207 OTPCalculator_Free(&mc->calc);
208 fail0:
209 return 0;
210 }
211  
212 void OTPChecker_Free (OTPChecker *mc)
213 {
214 DebugObject_Free(&mc->d_obj);
215  
216 // free work
217 if (mc->tw_have) {
218 BThreadWork_Free(&mc->tw);
219 }
220  
221 // free entries
222 BFree(mc->entries);
223  
224 // free tables
225 BFree(mc->tables);
226  
227 // free calculator
228 OTPCalculator_Free(&mc->calc);
229 }
230  
231 void OTPChecker_AddSeed (OTPChecker *mc, uint16_t seed_id, uint8_t *key, uint8_t *iv)
232 {
233 ASSERT(mc->next_table >= 0)
234 ASSERT(mc->next_table < mc->num_tables)
235 DebugObject_Access(&mc->d_obj);
236  
237 // free existing work
238 if (mc->tw_have) {
239 BThreadWork_Free(&mc->tw);
240 }
241  
242 // set table's seed ID
243 mc->tables[mc->next_table].id = seed_id;
244  
245 // copy key and IV
246 memcpy(mc->tw_key, key, BEncryption_cipher_key_size(mc->cipher));
247 memcpy(mc->tw_iv, iv, BEncryption_cipher_block_size(mc->cipher));
248  
249 // start work
250 BThreadWork_Init(&mc->tw, mc->twd, (BThreadWork_handler_done)work_done_handler, mc, (BThreadWork_work_func)work_func, mc);
251  
252 // set have work
253 mc->tw_have = 1;
254 }
255  
256 void OTPChecker_RemoveSeeds (OTPChecker *mc)
257 {
258 DebugObject_Access(&mc->d_obj);
259  
260 // free existing work
261 if (mc->tw_have) {
262 BThreadWork_Free(&mc->tw);
263 mc->tw_have = 0;
264 }
265  
266 mc->tables_used = 0;
267 mc->next_table = 0;
268 }
269  
270 int OTPChecker_CheckOTP (OTPChecker *mc, uint16_t seed_id, otp_t otp)
271 {
272 DebugObject_Access(&mc->d_obj);
273  
274 // try tables in reverse order
275 for (int i = 1; i <= mc->tables_used; i++) {
276 int table_index = bmodadd_int(mc->next_table, mc->num_tables - i, mc->num_tables);
277 if (table_index == mc->next_table && mc->tw_have) {
278 // ignore table that is being generated
279 continue;
280 }
281  
282 struct OTPChecker_table *table = &mc->tables[table_index];
283 if (table->id == seed_id) {
284 return OTPChecker_Table_CheckOTP(mc, table, otp);
285 }
286 }
287  
288 return 0;
289 }
290  
291 void OTPChecker_SetHandlers (OTPChecker *mc, OTPChecker_handler handler, void *user)
292 {
293 DebugObject_Access(&mc->d_obj);
294  
295 mc->handler = handler;
296 mc->user = user;
297 }