Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/iv_manager.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2011-2016 Tobias Brunner
3: * HSR Hochschule fuer Technik Rapperswil
4: *
5: * This program is free software; you can redistribute it and/or modify it
6: * under the terms of the GNU General Public License as published by the
7: * Free Software Foundation; either version 2 of the License, or (at your
8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9: *
10: * This program is distributed in the hope that it will be useful, but
11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13: * for more details.
14: */
15:
16: #include "iv_manager.h"
17:
18: #include <library.h>
19: #include <collections/linked_list.h>
20:
21: /**
22: * Max. number of IVs/QMs to track.
23: */
24: #define MAX_EXCHANGES_DEFAULT 3
25:
26: typedef struct private_iv_manager_t private_iv_manager_t;
27: typedef struct iv_data_t iv_data_t;
28: typedef struct qm_data_t qm_data_t;
29:
30: /**
31: * Data stored for IVs.
32: */
33: struct iv_data_t {
34: /**
35: * message ID
36: */
37: uint32_t mid;
38:
39: /**
40: * current IV
41: */
42: chunk_t iv;
43:
44: /**
45: * last block of encrypted message
46: */
47: chunk_t last_block;
48: };
49:
50: /**
51: * Private data of a iv_manager_t object.
52: */
53: struct private_iv_manager_t {
54: /**
55: * Implement public interface.
56: */
57: iv_manager_t public;
58:
59: /**
60: * Phase 1 IV.
61: */
62: iv_data_t phase1_iv;
63:
64: /**
65: * Keep track of IVs for exchanges after phase 1. We store only a limited
66: * number of IVs in an MRU sort of way. Stores iv_data_t objects.
67: */
68: linked_list_t *ivs;
69:
70: /**
71: * Keep track of Nonces during Quick Mode exchanges. Only a limited number
72: * of QMs are tracked at the same time. Stores qm_data_t objects.
73: */
74: linked_list_t *qms;
75:
76: /**
77: * Max. number of IVs/Quick Modes to track.
78: */
79: int max_exchanges;
80:
81: /**
82: * Hasher used for IV generation.
83: */
84: hasher_t *hasher;
85:
86: /*
87: * Encryption algorithm the block size.
88: */
89: size_t block_size;
90: };
91:
92: /**
93: * Data stored for Quick Mode exchanges.
94: */
95: struct qm_data_t {
96: /**
97: * Message ID.
98: */
99: uint32_t mid;
100:
101: /**
102: * Ni_b (Nonce from first message).
103: */
104: chunk_t n_i;
105:
106: /**
107: * Nr_b (Nonce from second message).
108: */
109: chunk_t n_r;
110: };
111:
112: /**
113: * Destroy an iv_data_t object.
114: */
115: static void iv_data_destroy(iv_data_t *this)
116: {
117: chunk_free(&this->last_block);
118: chunk_free(&this->iv);
119: free(this);
120: }
121:
122: /**
123: * Destroy a qm_data_t object.
124: */
125: static void qm_data_destroy(qm_data_t *this)
126: {
127: chunk_free(&this->n_i);
128: chunk_free(&this->n_r);
129: free(this);
130: }
131:
132: /**
133: * Generate an IV.
134: */
135: static bool generate_iv(private_iv_manager_t *this, iv_data_t *iv)
136: {
137: if (iv->mid == 0 || iv->iv.ptr)
138: { /* use last block of previous encrypted message */
139: chunk_free(&iv->iv);
140: iv->iv = iv->last_block;
141: iv->last_block = chunk_empty;
142: }
143: else
144: {
145: /* initial phase 2 IV = hash(last_phase1_block | mid) */
146: uint32_t net;;
147: chunk_t data;
148:
149: net = htonl(iv->mid);
150: data = chunk_cata("cc", this->phase1_iv.iv, chunk_from_thing(net));
151: if (!this->hasher->allocate_hash(this->hasher, data, &iv->iv))
152: {
153: return FALSE;
154: }
155: if (iv->iv.len > this->block_size)
156: {
157: iv->iv.len = this->block_size;
158: }
159: }
160: DBG4(DBG_IKE, "next IV for MID %u %B", iv->mid, &iv->iv);
161: return TRUE;
162: }
163:
164: /**
165: * Try to find an IV for the given message ID, if not found, generate it.
166: */
167: static iv_data_t *lookup_iv(private_iv_manager_t *this, uint32_t mid)
168: {
169: enumerator_t *enumerator;
170: iv_data_t *iv, *found = NULL;
171:
172: if (mid == 0)
173: {
174: return &this->phase1_iv;
175: }
176:
177: enumerator = this->ivs->create_enumerator(this->ivs);
178: while (enumerator->enumerate(enumerator, &iv))
179: {
180: if (iv->mid == mid)
181: { /* IV gets moved to the front of the list */
182: this->ivs->remove_at(this->ivs, enumerator);
183: found = iv;
184: break;
185: }
186: }
187: enumerator->destroy(enumerator);
188: if (!found)
189: {
190: INIT(found,
191: .mid = mid,
192: );
193: if (!generate_iv(this, found))
194: {
195: iv_data_destroy(found);
196: return NULL;
197: }
198: }
199: this->ivs->insert_first(this->ivs, found);
200: /* remove least recently used IV if maximum reached */
201: if (this->ivs->get_count(this->ivs) > this->max_exchanges &&
202: this->ivs->remove_last(this->ivs, (void**)&iv) == SUCCESS)
203: {
204: iv_data_destroy(iv);
205: }
206: return found;
207: }
208:
209: METHOD(iv_manager_t, init_iv_chain, bool,
210: private_iv_manager_t *this, chunk_t data, hasher_t *hasher,
211: size_t block_size)
212: {
213: this->hasher = hasher;
214: this->block_size = block_size;
215:
216: if (!this->hasher->allocate_hash(this->hasher, data, &this->phase1_iv.iv))
217: {
218: return FALSE;
219: }
220: if (this->phase1_iv.iv.len > this->block_size)
221: {
222: this->phase1_iv.iv.len = this->block_size;
223: }
224: DBG4(DBG_IKE, "initial IV %B", &this->phase1_iv.iv);
225: return TRUE;
226: }
227:
228: METHOD(iv_manager_t, get_iv, bool,
229: private_iv_manager_t *this, uint32_t mid, chunk_t *out)
230: {
231: iv_data_t *iv;
232:
233: iv = lookup_iv(this, mid);
234: if (iv)
235: {
236: *out = iv->iv;
237: return TRUE;
238: }
239: return FALSE;
240: }
241:
242: METHOD(iv_manager_t, update_iv, bool,
243: private_iv_manager_t *this, uint32_t mid, chunk_t last_block)
244: {
245: iv_data_t *iv = lookup_iv(this, mid);
246: if (iv)
247: { /* update last block */
248: chunk_free(&iv->last_block);
249: iv->last_block = chunk_clone(last_block);
250: return TRUE;
251: }
252: return FALSE;
253: }
254:
255: METHOD(iv_manager_t, confirm_iv, bool,
256: private_iv_manager_t *this, uint32_t mid)
257: {
258: iv_data_t *iv = lookup_iv(this, mid);
259: if (iv)
260: {
261: return generate_iv(this, iv);
262: }
263: return FALSE;
264: }
265:
266: METHOD(iv_manager_t, lookup_quick_mode, void,
267: private_iv_manager_t *this, uint32_t mid, chunk_t **n_i, chunk_t **n_r)
268: {
269: enumerator_t *enumerator;
270: qm_data_t *qm, *found = NULL;
271:
272: enumerator = this->qms->create_enumerator(this->qms);
273: while (enumerator->enumerate(enumerator, &qm))
274: {
275: if (qm->mid == mid)
276: { /* state gets moved to the front of the list */
277: this->qms->remove_at(this->qms, enumerator);
278: found = qm;
279: break;
280: }
281: }
282: enumerator->destroy(enumerator);
283: if (!found)
284: {
285: INIT(found,
286: .mid = mid,
287: );
288: }
289:
290: *n_i = &found->n_i;
291: *n_r = &found->n_r;
292:
293: this->qms->insert_first(this->qms, found);
294: /* remove least recently used state if maximum reached */
295: if (this->qms->get_count(this->qms) > this->max_exchanges &&
296: this->qms->remove_last(this->qms, (void**)&qm) == SUCCESS)
297: {
298: qm_data_destroy(qm);
299: }
300: }
301:
302: METHOD(iv_manager_t, remove_quick_mode, void,
303: private_iv_manager_t *this, uint32_t mid)
304: {
305: enumerator_t *enumerator;
306: qm_data_t *qm;
307:
308: enumerator = this->qms->create_enumerator(this->qms);
309: while (enumerator->enumerate(enumerator, &qm))
310: {
311: if (qm->mid == mid)
312: {
313: this->qms->remove_at(this->qms, enumerator);
314: qm_data_destroy(qm);
315: break;
316: }
317: }
318: enumerator->destroy(enumerator);
319: }
320:
321: METHOD(iv_manager_t, destroy, void,
322: private_iv_manager_t *this)
323: {
324: chunk_free(&this->phase1_iv.iv);
325: chunk_free(&this->phase1_iv.last_block);
326: this->ivs->destroy_function(this->ivs, (void*)iv_data_destroy);
327: this->qms->destroy_function(this->qms, (void*)qm_data_destroy);
328: free(this);
329: }
330:
331: iv_manager_t *iv_manager_create(int max_exchanges)
332: {
333: private_iv_manager_t *this;
334:
335: INIT(this,
336: .public = {
337: .init_iv_chain = _init_iv_chain,
338: .get_iv = _get_iv,
339: .update_iv = _update_iv,
340: .confirm_iv = _confirm_iv,
341: .lookup_quick_mode = _lookup_quick_mode,
342: .remove_quick_mode = _remove_quick_mode,
343: .destroy = _destroy,
344: },
345: .ivs = linked_list_create(),
346: .qms = linked_list_create(),
347: .max_exchanges = max_exchanges,
348: );
349:
350: if (!this->max_exchanges)
351: {
352: this->max_exchanges = lib->settings->get_int(lib->settings,
353: "%s.max_ikev1_exchanges", MAX_EXCHANGES_DEFAULT, lib->ns);
354: }
355: return &this->public;
356: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>